unit.vala 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /*
  2. * Copyright (c) 2012-2026 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. public struct Unit
  8. {
  9. public static Hashtable _component_registry;
  10. public Database _db;
  11. public Guid _id;
  12. public Unit(Database db, Guid id)
  13. {
  14. _db = db;
  15. _id = id;
  16. }
  17. /// Loads the unit @a name.
  18. public static int load_unit(out Guid prefab_id, Database db, string name)
  19. {
  20. return db.add_from_resource_path(out prefab_id, name + ".unit");
  21. }
  22. public void create_empty()
  23. {
  24. _db.create(_id, OBJECT_TYPE_UNIT);
  25. }
  26. public void create(string? prefab)
  27. {
  28. create_empty();
  29. _db.set_resource(_id, "prefab", prefab);
  30. }
  31. public Value? get_component_property(Guid component_id, string key, Value? deffault = null)
  32. {
  33. Value? val;
  34. // Search in components
  35. val = _db.get_property(_id, "components");
  36. if (val != null) {
  37. if (((Gee.HashSet<Guid?>)val).contains(component_id))
  38. return _db.get_property(component_id, key, deffault);
  39. }
  40. // Search in modified_components
  41. val = _db.get_property(_id, "modified_components.#" + component_id.to_string() + "." + key);
  42. if (val != null)
  43. return val;
  44. // Search in prefab
  45. string? prefab = prefab();
  46. if (prefab != null) {
  47. // Convert prefab path to object ID.
  48. Guid prefab_id = GUID_ZERO;
  49. Unit.load_unit(out prefab_id, _db, prefab);
  50. Unit unit = Unit(_db, prefab_id);
  51. return unit.get_component_property(component_id, key, deffault);
  52. }
  53. return deffault;
  54. }
  55. public bool get_component_bool(Guid component_id, string key, bool deffault = false)
  56. {
  57. return (bool)get_component_property(component_id, key, deffault);
  58. }
  59. public double get_component_double(Guid component_id, string key, double deffault = 0.0)
  60. {
  61. return (double)get_component_property(component_id, key, deffault);
  62. }
  63. public string get_component_string(Guid component_id, string key, string deffault = "")
  64. {
  65. return (string)get_component_property(component_id, key, deffault);
  66. }
  67. public Vector3 get_component_vector3(Guid component_id, string key, Vector3 deffault = VECTOR3_ZERO)
  68. {
  69. return (Vector3)get_component_property(component_id, key, deffault);
  70. }
  71. public Quaternion get_component_quaternion(Guid component_id, string key, Quaternion deffault = QUATERNION_IDENTITY)
  72. {
  73. return (Quaternion)get_component_property(component_id, key, deffault);
  74. }
  75. public string? get_component_resource(Guid component_id, string key, string? deffault = null)
  76. {
  77. Resource deffault_res = { deffault };
  78. Value? val = get_component_property(component_id, key, deffault_res);
  79. if (val.holds(typeof(Resource)))
  80. return ((Resource)val).name;
  81. return (string?)val;
  82. }
  83. public Guid get_component_reference(Guid component_id, string key, Guid deffault = GUID_ZERO)
  84. {
  85. return (Guid)get_component_property(component_id, key, deffault);
  86. }
  87. public void set_component_bool(Guid component_id, string key, bool val)
  88. {
  89. // Search in components
  90. Value? components = _db.get_property(_id, "components");
  91. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  92. _db.set_bool(component_id, key, val);
  93. return;
  94. }
  95. _db.set_bool(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  96. }
  97. public void set_component_double(Guid component_id, string key, double val)
  98. {
  99. // Search in components
  100. Value? components = _db.get_property(_id, "components");
  101. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  102. _db.set_double(component_id, key, val);
  103. return;
  104. }
  105. _db.set_double(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  106. }
  107. public void set_component_string(Guid component_id, string key, string val)
  108. {
  109. // Search in components
  110. Value? components = _db.get_property(_id, "components");
  111. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  112. _db.set_string(component_id, key, val);
  113. return;
  114. }
  115. _db.set_string(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  116. }
  117. public void set_component_vector3(Guid component_id, string key, Vector3 val)
  118. {
  119. // Search in components
  120. Value? components = _db.get_property(_id, "components");
  121. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  122. _db.set_vector3(component_id, key, val);
  123. return;
  124. }
  125. _db.set_vector3(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  126. }
  127. public void set_component_quaternion(Guid component_id, string key, Quaternion val)
  128. {
  129. // Search in components
  130. Value? components = _db.get_property(_id, "components");
  131. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  132. _db.set_quaternion(component_id, key, val);
  133. return;
  134. }
  135. _db.set_quaternion(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  136. }
  137. public void set_component_resource(Guid component_id, string key, string? val)
  138. {
  139. // Search in components
  140. Value? components = _db.get_property(_id, "components");
  141. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  142. _db.set_resource(component_id, key, val);
  143. return;
  144. }
  145. _db.set_resource(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  146. }
  147. public void set_component_reference(Guid component_id, string key, Guid val)
  148. {
  149. // Search in components
  150. Value? components = _db.get_property(_id, "components");
  151. if (components != null && ((Gee.HashSet<Guid?>)components).contains(component_id)) {
  152. _db.set_reference(component_id, key, val);
  153. return;
  154. }
  155. _db.set_reference(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
  156. }
  157. /// Returns whether the @a unit_id has a component of type @a component_type.
  158. public static bool has_component_static(out Guid component_id, string component_type, Database db, Guid unit_id)
  159. {
  160. Value? val;
  161. component_id = GUID_ZERO;
  162. bool prefab_has_component = false;
  163. // If the component type is found inside the "components" array, the unit has the component
  164. // and it owns it.
  165. val = db.get_property(unit_id, "components");
  166. if (val != null) {
  167. foreach (Guid id in (Gee.HashSet<Guid?>)val) {
  168. if ((string)db.object_type(id) == component_type) {
  169. component_id = id;
  170. return true;
  171. }
  172. }
  173. }
  174. // Otherwise, search if any prefab has the component.
  175. string? prefab = db.get_resource(unit_id, "prefab");
  176. if (prefab != null) {
  177. // Convert prefab path to object ID.
  178. Guid prefab_id = GUID_ZERO;
  179. Unit.load_unit(out prefab_id, db, prefab);
  180. prefab_has_component = has_component_static(out component_id
  181. , component_type
  182. , db
  183. , prefab_id
  184. );
  185. }
  186. // If the prefab does not have the component, so does this unit.
  187. if (prefab_has_component)
  188. return db.get_property(unit_id, "deleted_components.#" + component_id.to_string()) == null;
  189. component_id = GUID_ZERO;
  190. return false;
  191. }
  192. /// Returns whether the unit has the component_type.
  193. public bool has_component(out Guid component_id, string component_type)
  194. {
  195. return Unit.has_component_static(out component_id, component_type, _db, _id);
  196. }
  197. public Vector3 local_position()
  198. {
  199. Vector3 position;
  200. Guid component_id;
  201. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  202. position = get_component_vector3(component_id, "data.position");
  203. else
  204. position = _db.get_vector3(_id, "position");
  205. return position;
  206. }
  207. public Quaternion local_rotation()
  208. {
  209. Quaternion rotation;
  210. Guid component_id;
  211. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  212. rotation = get_component_quaternion(component_id, "data.rotation");
  213. else
  214. rotation = _db.get_quaternion(_id, "rotation");
  215. return rotation;
  216. }
  217. public Vector3 local_scale()
  218. {
  219. Vector3 scale;
  220. Guid component_id;
  221. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  222. scale = get_component_vector3(component_id, "data.scale");
  223. else
  224. scale = _db.get_vector3(_id, "scale");
  225. return scale;
  226. }
  227. public void set_local_position(Vector3 position)
  228. {
  229. Guid component_id;
  230. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  231. set_component_vector3(component_id, "data.position", position);
  232. else
  233. _db.set_vector3(_id, "position", position);
  234. }
  235. public void set_local_rotation(Quaternion rotation)
  236. {
  237. Guid component_id;
  238. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  239. set_component_quaternion(component_id, "data.rotation", rotation);
  240. else
  241. _db.set_quaternion(_id, "rotation", rotation);
  242. }
  243. public void set_local_scale(Vector3 scale)
  244. {
  245. Guid component_id;
  246. if (has_component(out component_id, OBJECT_TYPE_TRANSFORM))
  247. set_component_vector3(component_id, "data.scale", scale);
  248. else
  249. _db.set_vector3(_id, "scale", scale);
  250. }
  251. // Adds the @a component_type to the unit and returns its ID.
  252. public Guid add_component_type(string component_type)
  253. {
  254. // Create a new component.
  255. Guid component_id = Guid.new_guid();
  256. _db.create(component_id, component_type);
  257. _db.add_to_set(_id, "components", component_id);
  258. return component_id;
  259. }
  260. /// Removes the @a component_type from the unit.
  261. public void remove_component_type(string component_type)
  262. {
  263. Guid component_id;
  264. if (has_component(out component_id, component_type)) {
  265. if (_id == _db.owner(component_id)) {
  266. _db.remove_from_set(_id, "components", component_id);
  267. _db.destroy(component_id);
  268. _db.add_restore_point((int)ActionType.DESTROY_OBJECTS, { component_id });
  269. } else {
  270. _db.set_bool(_id, "deleted_components.#" + component_id.to_string(), false);
  271. // Clean all modified_components keys that matches the deleted component ID.
  272. string[] unit_keys = _db.get_keys(_id);
  273. for (int ii = 0; ii < unit_keys.length; ++ii) {
  274. if (unit_keys[ii].has_prefix("modified_components.#" + component_id.to_string()))
  275. _db.set_null(_id, unit_keys[ii]);
  276. }
  277. _db.add_restore_point((int)ActionType.CHANGE_OBJECTS, { _id });
  278. }
  279. } else {
  280. logw("The unit has no such component type `%s`".printf(component_type));
  281. }
  282. }
  283. public static void register_component_type(string type, string depends_on)
  284. {
  285. if (_component_registry == null)
  286. _component_registry = new Hashtable();
  287. _component_registry[type] = depends_on;
  288. }
  289. public string? prefab()
  290. {
  291. return _db.get_resource(_id, "prefab");
  292. }
  293. /// Returns whether the unit has a prefab.
  294. public bool has_prefab()
  295. {
  296. return prefab() != null;
  297. }
  298. /// Returns whether the unit is a light unit.
  299. public bool is_light()
  300. {
  301. return has_prefab()
  302. && _db.get_resource(_id, "prefab") == "core/units/light";
  303. }
  304. /// Returns whether the unit is a camera unit.
  305. public bool is_camera()
  306. {
  307. return has_prefab()
  308. && _db.get_resource(_id, "prefab") == "core/units/camera";
  309. }
  310. public static void generate_add_component_commands(StringBuilder sb, Guid unit_id, Guid component_id, Database db)
  311. {
  312. Unit unit = Unit(db, unit_id);
  313. if (db.object_type(component_id) == OBJECT_TYPE_TRANSFORM) {
  314. string s = LevelEditorApi.add_tranform_component(unit_id
  315. , component_id
  316. , unit.get_component_vector3 (component_id, "data.position")
  317. , unit.get_component_quaternion(component_id, "data.rotation")
  318. , unit.get_component_vector3 (component_id, "data.scale")
  319. );
  320. sb.append(s);
  321. } else if (db.object_type(component_id) == OBJECT_TYPE_CAMERA) {
  322. string s = LevelEditorApi.add_camera_component(unit_id
  323. , component_id
  324. , unit.get_component_string(component_id, "data.projection")
  325. , unit.get_component_double(component_id, "data.fov")
  326. , unit.get_component_double(component_id, "data.far_range")
  327. , unit.get_component_double(component_id, "data.near_range")
  328. );
  329. sb.append(s);
  330. } else if (db.object_type(component_id) == OBJECT_TYPE_MESH_RENDERER) {
  331. string s = LevelEditorApi.add_mesh_renderer_component(unit_id
  332. , component_id
  333. , unit.get_component_resource(component_id, "data.mesh_resource")
  334. , unit.get_component_string(component_id, "data.geometry_name")
  335. , unit.get_component_resource(component_id, "data.material")
  336. , unit.get_component_bool (component_id, "data.visible")
  337. , unit.get_component_bool (component_id, "data.cast_shadows", true)
  338. );
  339. sb.append(s);
  340. } else if (db.object_type(component_id) == OBJECT_TYPE_SPRITE_RENDERER) {
  341. string s = LevelEditorApi.add_sprite_renderer_component(unit_id
  342. , component_id
  343. , unit.get_component_resource(component_id, "data.sprite_resource")
  344. , unit.get_component_resource(component_id, "data.material")
  345. , unit.get_component_double(component_id, "data.layer")
  346. , unit.get_component_double(component_id, "data.depth")
  347. , unit.get_component_bool (component_id, "data.visible")
  348. , unit.get_component_bool (component_id, "data.flip_x")
  349. , unit.get_component_bool (component_id, "data.flip_y")
  350. );
  351. sb.append(s);
  352. } else if (db.object_type(component_id) == OBJECT_TYPE_LIGHT) {
  353. string s = LevelEditorApi.add_light_component(unit_id
  354. , component_id
  355. , unit.get_component_string (component_id, "data.type")
  356. , unit.get_component_double (component_id, "data.range")
  357. , unit.get_component_double (component_id, "data.intensity")
  358. , unit.get_component_double (component_id, "data.spot_angle")
  359. , unit.get_component_vector3(component_id, "data.color")
  360. , unit.get_component_double (component_id, "data.shadow_bias", 0.0001)
  361. , unit.get_component_bool (component_id, "data.cast_shadows", true)
  362. );
  363. sb.append(s);
  364. } else if (db.object_type(component_id) == OBJECT_TYPE_ANIMATION_STATE_MACHINE) {
  365. string s = LevelEditorApi.add_animation_state_machine_component(unit_id
  366. , component_id
  367. , unit.get_component_resource(component_id, "data.state_machine_resource")
  368. );
  369. sb.append(s);
  370. } else if (db.object_type(component_id) == OBJECT_TYPE_MOVER) {
  371. sb.append(LevelEditorApi.add_mover_component(unit_id
  372. , component_id
  373. , unit.get_component_double(component_id, "data.height")
  374. , unit.get_component_double(component_id, "data.radius")
  375. , unit.get_component_double(component_id, "data.max_slope_angle")
  376. , unit.get_component_string(component_id, "data.collision_filter")
  377. ));
  378. } else if (db.object_type(component_id) == OBJECT_TYPE_FOG) {
  379. sb.append(LevelEditorApi.add_fog_component(unit_id, component_id));
  380. sb.append(LevelEditorApi.set_fog(unit_id
  381. , unit.get_component_vector3(component_id, "data.color")
  382. , unit.get_component_double (component_id, "data.density")
  383. , unit.get_component_double (component_id, "data.range_min")
  384. , unit.get_component_double (component_id, "data.range_max")
  385. , unit.get_component_double (component_id, "data.sun_blend")
  386. , unit.get_component_bool (component_id, "data.enabled")
  387. ));
  388. } else if (db.object_type(component_id) == OBJECT_TYPE_GLOBAL_LIGHTING) {
  389. sb.append(LevelEditorApi.add_global_lighting_component(unit_id, component_id));
  390. sb.append(LevelEditorApi.set_global_lighting(unit_id
  391. , unit.get_component_resource (component_id, "data.skydome_map")
  392. , unit.get_component_double (component_id, "data.skydome_intensity")
  393. , unit.get_component_vector3(component_id, "data.ambient_color")
  394. ));
  395. } else if (db.object_type(component_id) == OBJECT_TYPE_BLOOM) {
  396. sb.append(LevelEditorApi.add_bloom_component(unit_id, component_id));
  397. sb.append(LevelEditorApi.set_bloom(unit_id
  398. , unit.get_component_bool (component_id, "data.enabled")
  399. , unit.get_component_double(component_id, "data.threshold")
  400. , unit.get_component_double(component_id, "data.weight")
  401. , unit.get_component_double(component_id, "data.intensity")
  402. ));
  403. } else if (db.object_type(component_id) == OBJECT_TYPE_TONEMAP) {
  404. sb.append(LevelEditorApi.add_tonemap_component(unit_id, component_id));
  405. sb.append(LevelEditorApi.set_tonemap(unit_id
  406. , unit.get_component_string(component_id, "data.type")
  407. ));
  408. }
  409. }
  410. public static void spawn_unit(StringBuilder sb, Guid unit_id, Database db)
  411. {
  412. Unit unit = Unit(db, unit_id);
  413. string? prefab = unit.prefab();
  414. sb.append("editor_nv, editor_nq, editor_nm = Device.temp_count()");
  415. if (prefab != null) {
  416. sb.append(LevelEditorApi.spawn_unit(unit_id
  417. , prefab
  418. , unit.local_position()
  419. , unit.local_rotation()
  420. , unit.local_scale()
  421. ));
  422. generate_change_commands(sb, { unit_id }, db);
  423. } else {
  424. sb.append(LevelEditorApi.spawn_empty_unit(unit_id));
  425. Guid?[] components = db.get_set(unit_id, "components", new Gee.HashSet<Guid?>()).to_array();
  426. Gee.ArrayList<int> spawn_order = new Gee.ArrayList<int>();
  427. for (int i = 0; i < components.length; ++i)
  428. spawn_order.add(i);
  429. spawn_order.sort((a, b) => {
  430. double order_a = db.get_double(components[a], "spawn_order");
  431. double order_b = db.get_double(components[b], "spawn_order");
  432. return (int)(order_a - order_b);
  433. });
  434. for (int i = 0; i < spawn_order.size; ++i) {
  435. Guid component_id = components[spawn_order[i]];
  436. generate_add_component_commands(sb, unit_id, component_id, db);
  437. }
  438. }
  439. sb.append("Device.set_temp_count(editor_nv, editor_nq, editor_nm)");
  440. }
  441. public static int generate_spawn_unit_commands(StringBuilder sb, Guid?[] object_ids, Database db)
  442. {
  443. int i;
  444. for (i = 0; i < object_ids.length; ++i) {
  445. if (db.object_type(object_ids[i]) == OBJECT_TYPE_UNIT) {
  446. if (!db.is_alive(object_ids[i]))
  447. continue;
  448. spawn_unit(sb, object_ids[i], db);
  449. Unit unit = Unit(db, object_ids[i]);
  450. if (db.has_property(unit._id, "children")) {
  451. Gee.HashSet<Guid?> children = db.get_set(unit._id, "children", new Gee.HashSet<Guid?>());
  452. generate_spawn_unit_commands(sb, children.to_array(), db);
  453. }
  454. Guid owner_id = db.owner(object_ids[i]);
  455. if (owner_id != GUID_ZERO && db.object_type(owner_id) == OBJECT_TYPE_UNIT)
  456. sb.append(LevelEditorApi.unit_set_parent(owner_id, object_ids[i]));
  457. } else if (Unit.is_component(object_ids[i], db)) {
  458. if (!db.is_alive(object_ids[i]))
  459. continue;
  460. Guid component_id = object_ids[i];
  461. Guid unit_id = db.owner(component_id);
  462. generate_add_component_commands(sb, unit_id, component_id, db);
  463. } else {
  464. break;
  465. }
  466. }
  467. return i;
  468. }
  469. public static int generate_destroy_commands(StringBuilder sb, Guid?[] object_ids, Database db)
  470. {
  471. int i;
  472. for (i = 0; i < object_ids.length; ++i) {
  473. if (db.object_type(object_ids[i]) == OBJECT_TYPE_UNIT) {
  474. sb.append(LevelEditorApi.destroy(object_ids[i]));
  475. } else if (is_component(object_ids[i], db)) {
  476. Guid component_id = object_ids[i];
  477. sb.append(LevelEditorApi.unit_destroy_component_type(db.owner(component_id), db.object_type(component_id)));
  478. } else {
  479. break;
  480. }
  481. }
  482. return i;
  483. }
  484. public static void generate_set_component_commands(StringBuilder sb, Guid unit_id, Guid component_id, Database db)
  485. {
  486. Unit unit = Unit(db, unit_id);
  487. string component_type = db.object_type(component_id);
  488. if (component_type == OBJECT_TYPE_TRANSFORM) {
  489. sb.append(LevelEditorApi.move_object(unit_id
  490. , unit.get_component_vector3 (component_id, "data.position")
  491. , unit.get_component_quaternion(component_id, "data.rotation")
  492. , unit.get_component_vector3 (component_id, "data.scale")
  493. ));
  494. } else if (component_type == OBJECT_TYPE_CAMERA) {
  495. sb.append(LevelEditorApi.set_camera(unit_id
  496. , unit.get_component_string(component_id, "data.projection")
  497. , unit.get_component_double(component_id, "data.fov")
  498. , unit.get_component_double(component_id, "data.far_range")
  499. , unit.get_component_double(component_id, "data.near_range")
  500. ));
  501. } else if (component_type == OBJECT_TYPE_MESH_RENDERER) {
  502. sb.append(LevelEditorApi.set_mesh(unit_id
  503. , unit.get_component_resource(component_id, "data.mesh_resource")
  504. , unit.get_component_string(component_id, "data.geometry_name")
  505. , unit.get_component_resource(component_id, "data.material")
  506. , unit.get_component_bool (component_id, "data.visible")
  507. , unit.get_component_bool (component_id, "data.cast_shadows", true)
  508. ));
  509. } else if (component_type == OBJECT_TYPE_SPRITE_RENDERER) {
  510. sb.append(LevelEditorApi.set_sprite(unit_id
  511. , unit.get_component_resource(component_id, "data.sprite_resource")
  512. , unit.get_component_resource(component_id, "data.material")
  513. , unit.get_component_double(component_id, "data.layer")
  514. , unit.get_component_double(component_id, "data.depth")
  515. , unit.get_component_bool (component_id, "data.visible")
  516. , unit.get_component_bool (component_id, "data.flip_x")
  517. , unit.get_component_bool (component_id, "data.flip_y")
  518. ));
  519. } else if (component_type == OBJECT_TYPE_LIGHT) {
  520. sb.append(LevelEditorApi.set_light(unit_id
  521. , unit.get_component_string (component_id, "data.type")
  522. , unit.get_component_double (component_id, "data.range")
  523. , unit.get_component_double (component_id, "data.intensity")
  524. , unit.get_component_double (component_id, "data.spot_angle")
  525. , unit.get_component_vector3(component_id, "data.color")
  526. , unit.get_component_double (component_id, "data.shadow_bias", 0.0001)
  527. , unit.get_component_bool (component_id, "data.cast_shadows", true)
  528. ));
  529. } else if (component_type == OBJECT_TYPE_ANIMATION_STATE_MACHINE) {
  530. sb.append(LevelEditorApi.set_animation_state_machine(unit_id
  531. , unit.get_component_resource(component_id, "data.state_machine_resource")
  532. ));
  533. } else if (component_type == OBJECT_TYPE_FOG) {
  534. sb.append(LevelEditorApi.set_fog(unit_id
  535. , unit.get_component_vector3(component_id, "data.color")
  536. , unit.get_component_double (component_id, "data.density")
  537. , unit.get_component_double (component_id, "data.range_min")
  538. , unit.get_component_double (component_id, "data.range_max")
  539. , unit.get_component_double (component_id, "data.sun_blend")
  540. , unit.get_component_bool (component_id, "data.enabled")
  541. ));
  542. } else if (component_type == OBJECT_TYPE_GLOBAL_LIGHTING) {
  543. sb.append(LevelEditorApi.set_global_lighting(unit_id
  544. , unit.get_component_resource (component_id, "data.skydome_map")
  545. , unit.get_component_double (component_id, "data.skydome_intensity")
  546. , unit.get_component_vector3(component_id, "data.ambient_color")
  547. ));
  548. } else if (component_type == OBJECT_TYPE_BLOOM) {
  549. sb.append(LevelEditorApi.set_bloom(unit_id
  550. , unit.get_component_bool (component_id, "data.enabled")
  551. , unit.get_component_double(component_id, "data.threshold")
  552. , unit.get_component_double(component_id, "data.weight")
  553. , unit.get_component_double(component_id, "data.intensity")
  554. ));
  555. } else if (component_type == OBJECT_TYPE_TONEMAP) {
  556. sb.append(LevelEditorApi.set_tonemap(unit_id
  557. , unit.get_component_string(component_id, "data.type")
  558. ));
  559. } else if (component_type == OBJECT_TYPE_SCRIPT) {
  560. /* No sync. */
  561. } else if (component_type == OBJECT_TYPE_COLLIDER) {
  562. /* No sync. */
  563. } else if (component_type == OBJECT_TYPE_ACTOR) {
  564. /* No sync. */
  565. } else if (component_type == OBJECT_TYPE_MOVER) {
  566. sb.append(LevelEditorApi.set_mover(unit_id
  567. , unit.get_component_double(component_id, "data.height")
  568. , unit.get_component_double(component_id, "data.radius")
  569. , unit.get_component_double(component_id, "data.max_slope_angle")
  570. , unit.get_component_vector3(component_id, "data.center")
  571. ));
  572. } else if (component_type == OBJECT_TYPE_ANIMATION_STATE_MACHINE) {
  573. /* No sync. */
  574. } else {
  575. logw("Unregistered component type `%s`".printf(component_type));
  576. }
  577. }
  578. public static int generate_change_commands(StringBuilder sb, Guid?[] object_ids, Database db)
  579. {
  580. int i;
  581. for (i = 0; i < object_ids.length; ++i) {
  582. if (db.object_type(object_ids[i]) == OBJECT_TYPE_UNIT) {
  583. Guid unit_id = object_ids[i];
  584. Unit unit = Unit(db, unit_id);
  585. sb.append("editor_nv, editor_nq, editor_nm = Device.temp_count()");
  586. sb.append(LevelEditorApi.move_object(unit_id
  587. , unit.local_position()
  588. , unit.local_rotation()
  589. , unit.local_scale()
  590. ));
  591. sb.append("Device.set_temp_count(editor_nv, editor_nq, editor_nm)");
  592. _component_registry.foreach((g) => {
  593. string component_type = g.key;
  594. Guid component_id;
  595. if (!unit.has_component(out component_id, component_type)) {
  596. sb.append(LevelEditorApi.unit_destroy_component_type(unit_id, component_type));
  597. return true;
  598. }
  599. generate_add_component_commands(sb, unit_id, component_id, db);
  600. generate_set_component_commands(sb, unit_id, component_id, db);
  601. return true;
  602. });
  603. } else if (Unit.is_component(object_ids[i], db)) {
  604. Guid component_id = object_ids[i];
  605. Guid unit_id = db.owner(component_id);
  606. generate_set_component_commands(sb, unit_id, component_id, db);
  607. } else {
  608. break;
  609. }
  610. }
  611. return i;
  612. }
  613. public static bool is_component(Guid id, Database db)
  614. {
  615. return (db.type_flags(StringId64(db.object_type(id))) & ObjectTypeFlags.UNIT_COMPONENT) != 0;
  616. }
  617. public void add_component_type_dependencies(ref Gee.ArrayList<Guid?> components_added, string component_type)
  618. {
  619. Guid dummy;
  620. if (has_component(out dummy, component_type))
  621. return;
  622. string[] component_type_dependencies = ((string)Unit._component_registry[component_type]).split(", ");
  623. foreach (unowned string dependency in component_type_dependencies) {
  624. Guid dependency_component_id;
  625. if (!has_component(out dependency_component_id, dependency))
  626. add_component_type_dependencies(ref components_added, dependency);
  627. }
  628. components_added.add(add_component_type(component_type));
  629. }
  630. }
  631. } /* namespace Crown */