unit.vala 27 KB

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