database.vala 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922
  1. /*
  2. * Copyright (c) 2012-2025 Daniele Bartolini et al.
  3. * SPDX-License-Identifier: GPL-3.0-or-later
  4. */
  5. namespace Crown
  6. {
  7. public enum PropertyType
  8. {
  9. BOOL,
  10. DOUBLE,
  11. STRING,
  12. VECTOR3,
  13. QUATERNION,
  14. OBJECTS_SET,
  15. OBJECT_NAME,
  16. OBJECT_REFERENCE,
  17. }
  18. public enum PropertyEditorType
  19. {
  20. DEFAULT, ///< Default editor for the property type.
  21. ENUM, ///< A string selected from a list.
  22. RESOURCE, ///< A resource name selected from a project.
  23. ANGLE, ///< An angle value displayed in degrees.
  24. COLOR, ///< An RGB color from a color picker.
  25. }
  26. public delegate void EnumCallback(InputField enum_property, InputEnum property, Project project);
  27. public delegate void ResourceCallback(InputField enum_property, InputResource property, Project project);
  28. public struct PropertyDefinition
  29. {
  30. public PropertyType type;
  31. public string name;
  32. public string? label;
  33. public PropertyEditorType editor;
  34. public Value? min;
  35. public Value? max;
  36. public Value? deffault;
  37. public string[] enum_values;
  38. public string[] enum_labels;
  39. public string? enum_property;
  40. public unowned EnumCallback? enum_callback;
  41. public unowned ResourceCallback? resource_callback;
  42. public string? resource_type;
  43. public StringId64 object_type;
  44. public bool hidden;
  45. public bool not_serialized;
  46. }
  47. public enum UndoRedoAction
  48. {
  49. RESTORE_POINT = int.MAX;
  50. }
  51. public struct RestorePointHeader
  52. {
  53. public uint32 id;
  54. public uint32 flags;
  55. public uint32 size;
  56. public uint32 num_guids;
  57. }
  58. public struct RestorePoint
  59. {
  60. public RestorePointHeader header;
  61. public Guid?[] data;
  62. }
  63. public class Stack
  64. {
  65. public uint32 _capacity;
  66. public uint8[] _data;
  67. public uint32 _read; // Position of the read/write head.
  68. public uint32 _size; // Size of the data written in the stack.
  69. public uint32 _last_write_restore_point_size; // Size when write_restore_point() was last called.
  70. ///
  71. public Stack(uint32 capacity)
  72. {
  73. assert(capacity > 0);
  74. _capacity = capacity;
  75. _data = new uint8[_capacity];
  76. clear();
  77. }
  78. ///
  79. public uint32 size()
  80. {
  81. return _size;
  82. }
  83. ///
  84. public void clear()
  85. {
  86. _read = 0;
  87. _size = 0;
  88. _last_write_restore_point_size = 0;
  89. }
  90. // Copies @a data into @a destination.
  91. public void copy_data(uint8* destination, void* data, ulong len)
  92. {
  93. uint8* source = (uint8*)data;
  94. for (ulong ii = 0; ii < len; ++ii)
  95. destination[ii] = source[ii];
  96. }
  97. // Writes @a data into the current page.
  98. public void write_data_internal(uint8* data, uint32 len)
  99. {
  100. assert(data != null);
  101. uint32 bytes_left = len;
  102. uint32 bytes_avail;
  103. // Write the data that wraps around.
  104. while (bytes_left > (bytes_avail = _capacity - _read)) {
  105. copy_data(&_data[_read]
  106. , ((uint8*)data) + (len - bytes_left)
  107. , bytes_avail
  108. );
  109. _read = (_read + bytes_avail) % _capacity;
  110. _size = uint32.min(_capacity, _size + bytes_avail);
  111. bytes_left -= bytes_avail;
  112. }
  113. // Write the remaining data.
  114. copy_data(&_data[_read]
  115. , ((uint8*)data) + (len - bytes_left)
  116. , bytes_left
  117. );
  118. _read += bytes_left;
  119. _size = uint32.min(_capacity, _size + bytes_left);
  120. _last_write_restore_point_size += len;
  121. }
  122. // Wrapper to avoid casting sizeof() manually.
  123. public void write_data(void* data, ulong len)
  124. {
  125. write_data_internal((uint8*)data, (uint32)len);
  126. }
  127. public void read_data_internal(uint8* data, uint32 len)
  128. {
  129. assert(data != null);
  130. uint32 bytes_left = len;
  131. // Read the data that wraps around.
  132. while (bytes_left > _read) {
  133. copy_data(data + bytes_left - _read
  134. , &_data[0]
  135. , _read
  136. );
  137. bytes_left -= _read;
  138. _size -= _read;
  139. assert(_size <= _capacity);
  140. _read = _capacity;
  141. }
  142. // Read the remaining data.
  143. copy_data(data
  144. , &_data[_read - bytes_left]
  145. , bytes_left
  146. );
  147. _read -= bytes_left;
  148. _size -= bytes_left;
  149. assert(_size <= _capacity);
  150. }
  151. // Wrapper to avoid casting sizeof() manually.
  152. public void read_data(void* data, ulong size)
  153. {
  154. read_data_internal((uint8*)data, (uint32)size);
  155. }
  156. public void write_bool(bool a)
  157. {
  158. write_data(&a, sizeof(bool));
  159. }
  160. public void write_uint32(uint32 a)
  161. {
  162. write_data(&a, sizeof(uint32));
  163. }
  164. public void write_double(double a)
  165. {
  166. write_data(&a, sizeof(double));
  167. }
  168. public void write_string(string str)
  169. {
  170. uint32 len = str.length;
  171. write_data(&str.data[0], len);
  172. write_data(&len, sizeof(uint32));
  173. }
  174. public void write_guid(Guid a)
  175. {
  176. write_data(&a, sizeof(Guid));
  177. }
  178. public void write_vector3(Vector3 a)
  179. {
  180. write_data(&a, sizeof(Vector3));
  181. }
  182. public void write_quaternion(Quaternion a)
  183. {
  184. write_data(&a, sizeof(Quaternion));
  185. }
  186. public bool read_bool()
  187. {
  188. bool a = false;
  189. read_data(&a, sizeof(bool));
  190. return a;
  191. }
  192. public int read_int()
  193. {
  194. int a = 0;
  195. read_data(&a, sizeof(int));
  196. return a;
  197. }
  198. public uint32 read_uint32()
  199. {
  200. uint32 a = 0;
  201. read_data(&a, sizeof(uint32));
  202. return a;
  203. }
  204. public double read_double()
  205. {
  206. double a = 0;
  207. read_data(&a, sizeof(double));
  208. return a;
  209. }
  210. public Guid read_guid()
  211. {
  212. Guid a = GUID_ZERO;
  213. read_data(&a, sizeof(Guid));
  214. return a;
  215. }
  216. public Vector3 read_vector3()
  217. {
  218. Vector3 a = VECTOR3_ZERO;
  219. read_data(&a, sizeof(Vector3));
  220. return a;
  221. }
  222. public Quaternion read_quaternion()
  223. {
  224. Quaternion a = QUATERNION_IDENTITY;
  225. read_data(&a, sizeof(Quaternion));
  226. return a;
  227. }
  228. public string read_string()
  229. {
  230. uint32 len = 0;
  231. read_data(&len, sizeof(uint32));
  232. uint8[] str = new uint8[len + 1];
  233. read_data(str, len);
  234. str[len] = '\0';
  235. return (string)str;
  236. }
  237. public void write_create_action(uint32 action, Guid id, string type)
  238. {
  239. write_string(type);
  240. write_guid(id);
  241. write_uint32(action);
  242. }
  243. public void write_destroy_action(uint32 action, Guid id, string type)
  244. {
  245. write_string(type);
  246. write_guid(id);
  247. write_uint32(action);
  248. }
  249. public void write_set_property_null_action(uint32 action, Guid id, string key)
  250. {
  251. // No value to push
  252. write_string(key);
  253. write_guid(id);
  254. write_uint32(action);
  255. }
  256. public void write_set_property_bool_action(uint32 action, Guid id, string key, bool val)
  257. {
  258. write_bool(val);
  259. write_string(key);
  260. write_guid(id);
  261. write_uint32(action);
  262. }
  263. public void write_set_property_double_action(uint32 action, Guid id, string key, double val)
  264. {
  265. write_double(val);
  266. write_string(key);
  267. write_guid(id);
  268. write_uint32(action);
  269. }
  270. public void write_set_property_string_action(uint32 action, Guid id, string key, string val)
  271. {
  272. write_string(val);
  273. write_string(key);
  274. write_guid(id);
  275. write_uint32(action);
  276. }
  277. public void write_set_property_guid_action(uint32 action, Guid id, string key, Guid val)
  278. {
  279. write_guid(val);
  280. write_string(key);
  281. write_guid(id);
  282. write_uint32(action);
  283. }
  284. public void write_set_property_vector3_action(uint32 action, Guid id, string key, Vector3 val)
  285. {
  286. write_vector3(val);
  287. write_string(key);
  288. write_guid(id);
  289. write_uint32(action);
  290. }
  291. public void write_set_property_quaternion_action(uint32 action, Guid id, string key, Quaternion val)
  292. {
  293. write_quaternion(val);
  294. write_string(key);
  295. write_guid(id);
  296. write_uint32(action);
  297. }
  298. public void write_add_to_set_action(uint32 action, Guid id, string key, Guid item_id)
  299. {
  300. write_guid(item_id);
  301. write_string(key);
  302. write_guid(id);
  303. write_uint32(action);
  304. }
  305. public void write_remove_from_set_action(uint32 action, Guid id, string key, Guid item_id)
  306. {
  307. write_guid(item_id);
  308. write_string(key);
  309. write_guid(id);
  310. write_uint32(action);
  311. }
  312. public void write_restore_point(uint32 id, uint32 flags, Guid?[] data)
  313. {
  314. uint32 size = _last_write_restore_point_size;
  315. uint32 num_guids = data.length;
  316. for (uint32 i = 0; i < num_guids; ++i)
  317. write_guid(data[num_guids - 1 - i]);
  318. write_uint32(num_guids);
  319. write_uint32(size);
  320. write_uint32(flags);
  321. write_uint32(id);
  322. write_uint32(UndoRedoAction.RESTORE_POINT);
  323. _last_write_restore_point_size = 0;
  324. }
  325. public RestorePoint read_restore_point()
  326. {
  327. uint32 t = read_uint32();
  328. assert(t == UndoRedoAction.RESTORE_POINT);
  329. uint32 id = read_uint32();
  330. uint32 flags = read_uint32();
  331. uint32 size = read_uint32();
  332. uint32 num_guids = read_uint32();
  333. Guid?[] ids = new Guid?[num_guids];
  334. for (uint32 i = 0; i < num_guids; ++i)
  335. ids[i] = read_guid();
  336. RestorePointHeader rph = { id, flags, size, num_guids };
  337. return { rph, ids };
  338. }
  339. }
  340. public class UndoRedo
  341. {
  342. public Stack _undo;
  343. public Stack _redo;
  344. ///
  345. public UndoRedo(uint32 undo_redo_size = 0)
  346. {
  347. uint32 size = uint32.max(1024, undo_redo_size);
  348. _undo = new Stack(size);
  349. _redo = new Stack(size);
  350. }
  351. public void reset()
  352. {
  353. _undo.clear();
  354. _redo.clear();
  355. }
  356. }
  357. const string OBJECT_NAME_UNNAMED = "Unnamed";
  358. public enum ObjectTypeFlags
  359. {
  360. NONE = 0,
  361. UNIT_COMPONENT = 1 << 0,
  362. }
  363. public struct PropertiesSlice
  364. {
  365. int start; // Index of first property.
  366. int end; // Index of last property + 1.
  367. }
  368. public struct ObjectTypeInfo
  369. {
  370. PropertiesSlice properties;
  371. string name;
  372. double ui_order;
  373. ObjectTypeFlags flags;
  374. string? user_data;
  375. }
  376. public class Database
  377. {
  378. public static bool _debug = false;
  379. public static bool _debug_getters = false;
  380. public enum Action
  381. {
  382. CREATE,
  383. DESTROY,
  384. SET_PROPERTY_NULL,
  385. SET_PROPERTY_BOOL,
  386. SET_PROPERTY_DOUBLE,
  387. SET_PROPERTY_STRING,
  388. SET_PROPERTY_GUID,
  389. SET_PROPERTY_VECTOR3,
  390. SET_PROPERTY_QUATERNION,
  391. ADD_TO_SET,
  392. REMOVE_FROM_SET
  393. }
  394. // Data
  395. private PropertyDefinition[] _property_definitions;
  396. public Gee.HashMap<StringId64?, ObjectTypeInfo?> _object_definitions;
  397. public Gee.HashMap<Guid?, Gee.HashMap<string, Value?>> _data;
  398. public UndoRedo? _undo_redo;
  399. public UndoRedo? _undo_redo_restore;
  400. public Project _project;
  401. // The number of changes to the database since the last successful state
  402. // synchronization (load(), save() etc.). If it is less than 0, the changes
  403. // came from undo(), otherwise they came from redo() or from regular calls to
  404. // create(), destroy(), set_*() etc. A value of 0 means there were no changes.
  405. public int _distance_from_last_sync;
  406. public int _distance_restore;
  407. // Signals
  408. public signal void object_type_added(ObjectTypeInfo info);
  409. public signal void objects_created(Guid?[] object_ids, uint32 flags);
  410. public signal void objects_destroyed(Guid?[] object_ids, uint32 flags);
  411. public signal void objects_changed(Guid?[] object_ids, uint32 flags);
  412. public Database(Project project, UndoRedo? undo_redo = null)
  413. {
  414. _property_definitions = new PropertyDefinition[0];
  415. _object_definitions = new Gee.HashMap<StringId64?, ObjectTypeInfo?>(StringId64.hash_func, StringId64.equal_func);
  416. _data = new Gee.HashMap<Guid?, Gee.HashMap<string, Value?>>(Guid.hash_func, Guid.equal_func);
  417. _project = project;
  418. _undo_redo = undo_redo;
  419. _undo_redo_restore = null;
  420. reset();
  421. }
  422. /// Resets database to clean state.
  423. public void reset()
  424. {
  425. _data.clear();
  426. if (_undo_redo != null)
  427. _undo_redo.reset();
  428. _distance_from_last_sync = 0;
  429. _distance_restore = 0;
  430. // This is a special field which stores all objects
  431. _data[GUID_ZERO] = new Gee.HashMap<string, Value?>();
  432. }
  433. /// Returns whether the database has been changed since last call to Save().
  434. public bool changed()
  435. {
  436. return _distance_from_last_sync != 0;
  437. }
  438. /// Saves database to path without marking it as not changed.
  439. public int dump(string path, Guid id)
  440. {
  441. try {
  442. Hashtable json = encode(id);
  443. SJSON.save(json, path);
  444. return 0;
  445. } catch (JsonWriteError e) {
  446. return -1;
  447. }
  448. }
  449. /// Saves database to path.
  450. public int save(string path, Guid id)
  451. {
  452. int err = dump(path, id);
  453. if (err == 0)
  454. _distance_from_last_sync = 0;
  455. return err;
  456. }
  457. public void disable_undo()
  458. {
  459. _undo_redo_restore = _undo_redo;
  460. _undo_redo = null;
  461. _distance_restore = _distance_from_last_sync;
  462. }
  463. public void restore_undo()
  464. {
  465. _undo_redo = _undo_redo_restore;
  466. _undo_redo_restore = null;
  467. _distance_from_last_sync = _distance_restore;
  468. }
  469. // See: add_from_path().
  470. public int add_from_file(out Guid object_id, FileStream? fs, string resource_path)
  471. {
  472. disable_undo();
  473. try {
  474. Hashtable json = SJSON.load_from_file(fs);
  475. // Parse the object's ID or generate a new one if none is found.
  476. if (json.has_key("id"))
  477. object_id = Guid.parse((string)json["id"]);
  478. else if (json.has_key("_guid"))
  479. object_id = Guid.parse((string)json["_guid"]);
  480. else
  481. object_id = Guid.new_guid();
  482. string type = ResourceId.type(resource_path);
  483. StringId64 type_hash = StringId64(type);
  484. _data[object_id] = new Gee.HashMap<string, Value?>();
  485. set_object_type(object_id, type);
  486. set_object_owner(object_id, GUID_ZERO);
  487. set_object_alive(object_id, true);
  488. if (has_object_type(type_hash))
  489. _init_object(object_id, object_definition(type_hash));
  490. decode_object(object_id, GUID_ZERO, "", json);
  491. // Create a mapping between the path and the object it has been loaded into.
  492. set_property_internal(0, GUID_ZERO, resource_path, object_id);
  493. restore_undo();
  494. return 0;
  495. } catch (JsonSyntaxError e) {
  496. object_id = GUID_ZERO;
  497. restore_undo();
  498. return -1;
  499. }
  500. }
  501. // Adds the object stored at @a path to the database.
  502. // This makes it possible to load multiple objects from distinct
  503. // paths in the same database. @a resource_path is used as a key in the
  504. // database to refer to the object that has been loaded. This is useful when
  505. // you do not have the object ID but only its path, as it is often the case
  506. // since resources use paths and not IDs to reference each other.
  507. public int add_from_path(out Guid object_id, string path, string resource_path)
  508. {
  509. object_id = GUID_ZERO;
  510. FileStream fs = FileStream.open(path, "rb");
  511. if (fs == null)
  512. return 1;
  513. return add_from_file(out object_id, fs, resource_path);
  514. }
  515. public int add_from_resource_path(out Guid object_id, string resource_path)
  516. {
  517. // If the resource is already loaded.
  518. if (has_property(GUID_ZERO, resource_path)) {
  519. object_id = get_property_guid(GUID_ZERO, resource_path);
  520. return 0;
  521. }
  522. string path = _project.absolute_path(resource_path);
  523. return add_from_path(out object_id, path, resource_path);
  524. }
  525. /// Loads the database with the object stored at @a path.
  526. public int load_from_file(out Guid object_id, FileStream fs, string resource_path)
  527. {
  528. reset();
  529. return add_from_file(out object_id, fs, resource_path);
  530. }
  531. /// Loads the database with the object stored at @a path.
  532. public int load_from_path(out Guid object_id, string path, string resource_path)
  533. {
  534. reset();
  535. return add_from_path(out object_id, path, resource_path);
  536. }
  537. /// Encodes the object @a id into SJSON object.
  538. public Hashtable encode(Guid id)
  539. {
  540. return encode_object(id, get_data(id));
  541. }
  542. public static bool is_valid_value(Value? value)
  543. {
  544. return value == null
  545. || value.holds(typeof(bool))
  546. || value.holds(typeof(double))
  547. || value.holds(typeof(string))
  548. || value.holds(typeof(Guid))
  549. || value.holds(typeof(Vector3))
  550. || value.holds(typeof(Quaternion))
  551. ;
  552. }
  553. public static bool is_valid_key(string key)
  554. {
  555. return key.length > 0
  556. && !key.has_prefix(".")
  557. && !key.has_suffix(".")
  558. ;
  559. }
  560. public static string debug_string(Value? value)
  561. {
  562. if (value == null)
  563. return "null";
  564. if (value.holds(typeof(bool)))
  565. return ((bool)value).to_string();
  566. if (value.holds(typeof(double)))
  567. return ((double)value).to_string();
  568. if (value.holds(typeof(string)))
  569. return ((string)value).to_string();
  570. if (value.holds(typeof(Guid)))
  571. return ((Guid)value).to_debug_string();
  572. if (value.holds(typeof(Vector3)))
  573. return ((Vector3)value).to_string();
  574. if (value.holds(typeof(Quaternion)))
  575. return ((Quaternion)value).to_string();
  576. if (value.holds(typeof(Gee.HashSet)))
  577. return "Set<Guid>";
  578. return "<invalid>";
  579. }
  580. public void decode_object(Guid id, Guid owner_id, string db_key, Hashtable json)
  581. {
  582. string old_db = db_key;
  583. string k = db_key;
  584. // The "type" key defines object type only if it appears
  585. // in the root of a JSON object (k == "").
  586. if (k == "") {
  587. string? type = null;
  588. if (json.has_key("_type"))
  589. type = (string)json["_type"];
  590. else if (json.has_key("type"))
  591. type = (string)json["type"];
  592. if (type != null) {
  593. set_object_type(id, type);
  594. StringId64 type_hash = StringId64(type);
  595. if (has_object_type(type_hash))
  596. _init_object(id, object_definition(type_hash));
  597. }
  598. }
  599. string[] keys = json.keys.to_array();
  600. foreach (string key in keys) {
  601. // ID is filled by decode_set().
  602. if (key == "id" || key == "_guid" || key == "_alive")
  603. continue;
  604. Value? val = json[key];
  605. k += k == "" ? key : ("." + key);
  606. if (val.holds(typeof(Hashtable))) {
  607. Hashtable ht = (Hashtable)val;
  608. decode_object(id, owner_id, k, ht);
  609. } else if (val.holds(typeof(Gee.ArrayList))) {
  610. Gee.ArrayList<Value?> arr = (Gee.ArrayList<Value?>)val;
  611. if (arr.size > 0
  612. && arr[0].holds(typeof(double))
  613. && k != "frames" // sprite_animation
  614. )
  615. set_property_internal(0, id, k, decode_value(val));
  616. else
  617. decode_set(id, key, arr);
  618. } else {
  619. set_property_internal(0, id, k, decode_value(val));
  620. }
  621. k = old_db;
  622. }
  623. }
  624. public void decode_set(Guid owner_id, string key, Gee.ArrayList<Value?> json)
  625. {
  626. // Set should be created even if it is empty.
  627. create_empty_set(owner_id, key);
  628. for (int i = 0; i < json.size; ++i) {
  629. Hashtable obj;
  630. string owner_type = object_type(owner_id);
  631. if (owner_type == OBJECT_TYPE_SPRITE_ANIMATION)
  632. obj = new Hashtable();
  633. else
  634. obj = (Hashtable)json[i];
  635. // Decode object ID.
  636. Guid obj_id;
  637. if (obj.has_key("id") && owner_type != OBJECT_TYPE_FONT)
  638. obj_id = Guid.parse((string)obj["id"]);
  639. else if (obj.has_key("_guid"))
  640. obj_id = Guid.parse((string)obj["_guid"]);
  641. else
  642. obj_id = Guid.new_guid();
  643. _data[obj_id] = new Gee.HashMap<string, Value?>();
  644. // Determine the object's type based on the type of its
  645. // parent and other heuristics.
  646. if (owner_type == OBJECT_TYPE_LEVEL) {
  647. if (key == "units")
  648. set_object_type(obj_id, OBJECT_TYPE_UNIT);
  649. else if (key == "sounds")
  650. set_object_type(obj_id, OBJECT_TYPE_SOUND_SOURCE);
  651. else
  652. set_object_type(obj_id, "undefined");
  653. } else if (owner_type == OBJECT_TYPE_STATE_MACHINE) {
  654. if (key == "states")
  655. set_object_type(obj_id, OBJECT_TYPE_STATE_MACHINE_NODE);
  656. else if (key == "variables")
  657. set_object_type(obj_id, OBJECT_TYPE_STATE_MACHINE_VARIABLE);
  658. else
  659. set_object_type(obj_id, "undefined");
  660. } else if (owner_type == OBJECT_TYPE_STATE_MACHINE_NODE) {
  661. if (key == "animations")
  662. set_object_type(obj_id, OBJECT_TYPE_NODE_ANIMATION);
  663. else if (key == "transitions")
  664. set_object_type(obj_id, OBJECT_TYPE_NODE_TRANSITION);
  665. } else if (owner_type == OBJECT_TYPE_SPRITE) {
  666. if (key == "frames") {
  667. set_object_type(obj_id, "sprite_frame");
  668. set_property_internal(0, obj_id, "index", (double)i);
  669. }
  670. } else if (owner_type == OBJECT_TYPE_SPRITE_ANIMATION) {
  671. if (key == "frames") {
  672. set_object_type(obj_id, "animation_frame");
  673. set_property_internal(0, obj_id, "index", (double)json[i]);
  674. }
  675. } else if (owner_type == OBJECT_TYPE_FONT) {
  676. if (key == "glyphs") {
  677. set_object_type(obj_id, "font_glyph");
  678. set_property_internal(0, obj_id, "cp", (double)obj["id"]);
  679. }
  680. }
  681. set_object_owner(obj_id, owner_id);
  682. set_object_alive(obj_id, true);
  683. decode_object(obj_id, owner_id, "", obj);
  684. assert(has_property(obj_id, "_type"));
  685. add_to_set_internal(0, owner_id, key, obj_id);
  686. }
  687. }
  688. public Value? decode_value(Value? value)
  689. {
  690. if (value.holds(typeof(Gee.ArrayList))) {
  691. Gee.ArrayList<Value?> al = (Gee.ArrayList<Value?>)value;
  692. if (al.size == 1)
  693. return Vector3((double)al[0], 0.0, 0.0);
  694. else if (al.size == 2)
  695. return Vector3((double)al[0], (double)al[1], 0.0);
  696. else if (al.size == 3)
  697. return Vector3((double)al[0], (double)al[1], (double)al[2]);
  698. else if (al.size == 4)
  699. return Quaternion((double)al[0], (double)al[1], (double)al[2], (double)al[3]);
  700. else
  701. return Vector3(0.0, 0.0, 0.0);
  702. } else if (value.holds(typeof(string))) {
  703. Guid id;
  704. if (Guid.try_parse((string)value, out id))
  705. return id;
  706. return value;
  707. } else if (value == null
  708. || value.holds(typeof(bool))
  709. || value.holds(typeof(double))) {
  710. return value;
  711. } else {
  712. return null;
  713. }
  714. }
  715. public Hashtable encode_object_compat(Guid id, Gee.HashMap<string, Value?> db)
  716. {
  717. Hashtable obj = new Hashtable();
  718. if (id != GUID_ZERO)
  719. obj["_guid"] = id.to_string();
  720. string[] keys = db.keys.to_array();
  721. foreach (string key in keys) {
  722. // Since null-key is equivalent to non-existent key, skip serialization.
  723. if (db[key] == null || key == "_owner" || key == "_alive")
  724. continue;
  725. string[] foo = key.split(".");
  726. Hashtable x = obj;
  727. if (foo.length > 1) {
  728. for (int i = 0; i < foo.length - 1; ++i) {
  729. string f = foo[i];
  730. if (x.has_key(f)) {
  731. x = (Hashtable)x[f];
  732. continue;
  733. }
  734. Hashtable y = new Hashtable();
  735. x.set(f, y);
  736. x = y;
  737. }
  738. }
  739. x.set(foo[foo.length - 1], encode_value(db[key]));
  740. }
  741. return obj;
  742. }
  743. public Hashtable encode_object(Guid id, Gee.HashMap<string, Value?> db)
  744. {
  745. assert(object_is_alive(id));
  746. string type = object_type(id);
  747. PropertyDefinition[]? properties = object_definition(StringId64(type));
  748. if (type == OBJECT_TYPE_UNIT || properties == null)
  749. return encode_object_compat(id, db);
  750. Hashtable obj = new Hashtable();
  751. if (id != GUID_ZERO) {
  752. obj["_guid"] = id.to_string();
  753. obj["_type"] = type;
  754. }
  755. foreach (PropertyDefinition def in properties) {
  756. if (def.not_serialized)
  757. continue;
  758. // Since null-key is equivalent to non-existent key, skip serialization.
  759. if (db[def.name] == null)
  760. continue;
  761. string[] foo = def.name.split(".");
  762. Hashtable x = obj;
  763. if (foo.length > 1) {
  764. for (int i = 0; i < foo.length - 1; ++i) {
  765. string f = foo[i];
  766. if (x.has_key(f)) {
  767. x = (Hashtable)x[f];
  768. continue;
  769. }
  770. Hashtable y = new Hashtable();
  771. x.set(f, y);
  772. x = y;
  773. }
  774. }
  775. x.set(foo[foo.length - 1], encode_value(db[def.name]));
  776. }
  777. return obj;
  778. }
  779. public Value? encode_value(Value? value)
  780. {
  781. assert(is_valid_value(value) || value.holds(typeof(Gee.HashSet)));
  782. if (value.holds(typeof(Vector3))) {
  783. Vector3 v = (Vector3)value;
  784. Gee.ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  785. arr.add(v.x);
  786. arr.add(v.y);
  787. arr.add(v.z);
  788. return arr;
  789. } else if (value.holds(typeof(Quaternion))) {
  790. Quaternion q = (Quaternion)value;
  791. Gee.ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  792. arr.add(q.x);
  793. arr.add(q.y);
  794. arr.add(q.z);
  795. arr.add(q.w);
  796. return arr;
  797. } else if (value.holds(typeof(Guid))) {
  798. Guid id = (Guid)value;
  799. return id.to_string();
  800. } else if (value.holds(typeof(Gee.HashSet))) {
  801. Gee.HashSet<Guid?> hs = (Gee.HashSet<Guid?>)value;
  802. Gee.ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  803. foreach (Guid id in hs) {
  804. if (!object_is_alive(id))
  805. continue;
  806. arr.add(encode_object(id, get_data(id)));
  807. }
  808. return arr;
  809. } else {
  810. return value;
  811. }
  812. }
  813. public Gee.HashMap<string, Value?> get_data(Guid id)
  814. {
  815. assert(has_object(id));
  816. return _data[id];
  817. }
  818. public void set_property_internal(int dir, Guid id, string key, Value? value)
  819. {
  820. assert(has_object(id));
  821. assert(is_valid_key(key));
  822. assert(is_valid_value(value));
  823. if (_debug)
  824. logi("set_property %s %s %s".printf(debug_string(id), key, debug_string(value)));
  825. Gee.HashMap<string, Value?> ob = get_data(id);
  826. ob[key] = value;
  827. _distance_from_last_sync += dir;
  828. }
  829. public void create_empty_set(Guid id, string key)
  830. {
  831. assert(has_object(id));
  832. assert(is_valid_key(key));
  833. Gee.HashMap<string, Value?> ob = get_data(id);
  834. ob[key] = new Gee.HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  835. }
  836. public void add_to_set_internal(int dir, Guid id, string key, Guid item_id)
  837. {
  838. assert(has_object(id));
  839. assert(is_valid_key(key));
  840. assert(item_id != GUID_ZERO);
  841. assert(has_object(item_id));
  842. if (_debug)
  843. logi("add_to_set %s %s %s".printf(debug_string(id), key, debug_string(item_id)));
  844. Gee.HashMap<string, Value?> ob = get_data(id);
  845. if (!ob.has_key(key)) {
  846. Gee.HashSet<Guid?> hs = new Gee.HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  847. hs.add(item_id);
  848. ob[key] = hs;
  849. } else {
  850. ((Gee.HashSet<Guid?>)ob[key]).add(item_id);
  851. }
  852. get_data(item_id)["_owner"] = id;
  853. _distance_from_last_sync += dir;
  854. }
  855. public void remove_from_set_internal(int dir, Guid id, string key, Guid item_id)
  856. {
  857. assert(has_object(id));
  858. assert(is_valid_key(key));
  859. assert(item_id != GUID_ZERO);
  860. if (_debug)
  861. logi("remove_from_set %s %s %s".printf(debug_string(id), key, debug_string(item_id)));
  862. Gee.HashMap<string, Value?> ob = get_data(id);
  863. ((Gee.HashSet<Guid?>)ob[key]).remove(item_id);
  864. set_object_owner(id, GUID_ZERO);
  865. _distance_from_last_sync += dir;
  866. }
  867. // Returns the type of the object @a id.
  868. public string object_type(Guid id)
  869. {
  870. assert(has_object(id));
  871. if (id == GUID_ZERO)
  872. return "database";
  873. else
  874. return (string)get_data(id)["_type"];
  875. }
  876. // Returns the owner of @a id.
  877. public Guid object_owner(Guid id)
  878. {
  879. assert(has_object(id));
  880. return (Guid)get_data(id)["_owner"];
  881. }
  882. // Sets the @a type of the object @a id.
  883. // This is called automatically when loading data or when new objects are created via create().
  884. // It can occasionally be called manually after loading legacy data with no type information
  885. // stored inside objects.
  886. public void set_object_type(Guid id, string type)
  887. {
  888. assert(has_object(id));
  889. get_data(id)["_type"] = type;
  890. }
  891. public void set_object_owner(Guid id, Guid owner_id)
  892. {
  893. assert(has_object(id));
  894. assert(has_object(owner_id));
  895. get_data(id)["_owner"] = owner_id;
  896. }
  897. public void set_object_alive(Guid id, bool alive)
  898. {
  899. assert(has_object(id));
  900. get_data(id)["_alive"] = alive;
  901. }
  902. public bool object_is_alive(Guid id)
  903. {
  904. assert(has_object(id));
  905. return (bool)get_data(id)["_alive"];
  906. }
  907. public void _init_object(Guid id, PropertyDefinition[] properties)
  908. {
  909. foreach (PropertyDefinition def in properties) {
  910. switch (def.type) {
  911. case PropertyType.BOOL:
  912. set_property_bool(id, def.name, (bool)def.deffault);
  913. break;
  914. case PropertyType.DOUBLE:
  915. set_property_double(id, def.name, (double)def.deffault);
  916. break;
  917. case PropertyType.STRING:
  918. set_property_string(id, def.name, (string)def.deffault);
  919. break;
  920. case PropertyType.OBJECT_REFERENCE:
  921. set_property_guid(id, def.name, (Guid)def.deffault);
  922. break;
  923. case PropertyType.VECTOR3:
  924. set_property_vector3(id, def.name, (Vector3)def.deffault);
  925. break;
  926. case PropertyType.QUATERNION:
  927. set_property_quaternion(id, def.name, (Quaternion)def.deffault);
  928. break;
  929. case PropertyType.OBJECTS_SET:
  930. create_empty_set(id, def.name);
  931. break;
  932. case PropertyType.OBJECT_NAME:
  933. if (def.deffault == null)
  934. set_property_null(id, def.name);
  935. else
  936. set_property_string(id, def.name, (string)def.deffault);
  937. break;
  938. default:
  939. assert(false);
  940. break;
  941. }
  942. }
  943. }
  944. public void create(Guid id, string type)
  945. {
  946. assert(id != GUID_ZERO);
  947. assert(!has_object(id));
  948. if (_debug)
  949. logi("create %s".printf(debug_string(id)));
  950. if (_undo_redo != null) {
  951. _undo_redo._undo.write_destroy_action(Action.DESTROY, id, type);
  952. _undo_redo._redo.clear();
  953. }
  954. _data[id] = new Gee.HashMap<string, Value?>();
  955. set_object_alive(id, true);
  956. set_object_type(id, type);
  957. StringId64 type_hash = StringId64(type);
  958. if (has_object_type(type_hash))
  959. _init_object(id, object_definition(type_hash));
  960. }
  961. public void destroy(Guid id)
  962. {
  963. assert(id != GUID_ZERO);
  964. assert(has_object(id));
  965. string obj_type = object_type(id);
  966. Gee.HashMap<string, Value?> o = get_data(id);
  967. string[] keys = o.keys.to_array();
  968. foreach (string key in keys) {
  969. Value? value = o[key];
  970. if (value.holds(typeof(Gee.HashSet))) {
  971. Gee.HashSet<Guid?> hs = (Gee.HashSet<Guid?>)value;
  972. Guid?[] ids = hs.to_array();
  973. foreach (Guid item_id in ids)
  974. destroy(item_id);
  975. }
  976. }
  977. set_object_alive(id, false);
  978. if (_undo_redo != null) {
  979. _undo_redo._undo.write_create_action(Action.CREATE, id, obj_type);
  980. _undo_redo._redo.clear();
  981. }
  982. if (_debug)
  983. logi("destroy %s".printf(debug_string(id)));
  984. }
  985. public void set_property_null(Guid id, string key)
  986. {
  987. assert(has_object(id));
  988. assert(is_valid_key(key));
  989. assert(is_valid_value(null));
  990. if (_undo_redo != null) {
  991. Gee.HashMap<string, Value?> ob = get_data(id);
  992. if (ob.has_key(key) && ob[key] != null) {
  993. if (ob[key].holds(typeof(bool)))
  994. _undo_redo._undo.write_set_property_bool_action(Action.SET_PROPERTY_BOOL, id, key, (bool)ob[key]);
  995. if (ob[key].holds(typeof(double)))
  996. _undo_redo._undo.write_set_property_double_action(Action.SET_PROPERTY_DOUBLE, id, key, (double)ob[key]);
  997. if (ob[key].holds(typeof(string)))
  998. _undo_redo._undo.write_set_property_string_action(Action.SET_PROPERTY_STRING, id, key, (string)ob[key]);
  999. if (ob[key].holds(typeof(Guid)))
  1000. _undo_redo._undo.write_set_property_guid_action(Action.SET_PROPERTY_GUID, id, key, (Guid)ob[key]);
  1001. if (ob[key].holds(typeof(Vector3)))
  1002. _undo_redo._undo.write_set_property_vector3_action(Action.SET_PROPERTY_VECTOR3, id, key, (Vector3)ob[key]);
  1003. if (ob[key].holds(typeof(Quaternion)))
  1004. _undo_redo._undo.write_set_property_quaternion_action(Action.SET_PROPERTY_QUATERNION, id, key, (Quaternion)ob[key]);
  1005. } else {
  1006. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1007. }
  1008. _undo_redo._redo.clear();
  1009. }
  1010. set_property_internal(1, id, key, null);
  1011. }
  1012. public void set_property_bool(Guid id, string key, bool val)
  1013. {
  1014. assert(has_object(id));
  1015. assert(is_valid_key(key));
  1016. assert(is_valid_value(val));
  1017. if (_undo_redo != null) {
  1018. Gee.HashMap<string, Value?> ob = get_data(id);
  1019. if (ob.has_key(key) && ob[key] != null)
  1020. _undo_redo._undo.write_set_property_bool_action(Action.SET_PROPERTY_BOOL, id, key, (bool)ob[key]);
  1021. else
  1022. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1023. _undo_redo._redo.clear();
  1024. }
  1025. set_property_internal(1, id, key, val);
  1026. }
  1027. public void set_property_double(Guid id, string key, double val)
  1028. {
  1029. assert(has_object(id));
  1030. assert(is_valid_key(key));
  1031. assert(is_valid_value(val));
  1032. if (_undo_redo != null) {
  1033. Gee.HashMap<string, Value?> ob = get_data(id);
  1034. if (ob.has_key(key) && ob[key] != null)
  1035. _undo_redo._undo.write_set_property_double_action(Action.SET_PROPERTY_DOUBLE, id, key, (double)ob[key]);
  1036. else
  1037. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1038. _undo_redo._redo.clear();
  1039. }
  1040. set_property_internal(1, id, key, val);
  1041. }
  1042. public void set_property_string(Guid id, string key, string val)
  1043. {
  1044. assert(has_object(id));
  1045. assert(is_valid_key(key));
  1046. assert(is_valid_value(val));
  1047. if (_undo_redo != null) {
  1048. Gee.HashMap<string, Value?> ob = get_data(id);
  1049. if (ob.has_key(key) && ob[key] != null)
  1050. _undo_redo._undo.write_set_property_string_action(Action.SET_PROPERTY_STRING, id, key, (string)ob[key]);
  1051. else
  1052. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1053. _undo_redo._redo.clear();
  1054. }
  1055. set_property_internal(1, id, key, val);
  1056. }
  1057. public void set_property_guid(Guid id, string key, Guid val)
  1058. {
  1059. assert(has_object(id));
  1060. assert(is_valid_key(key));
  1061. assert(is_valid_value(val));
  1062. if (_undo_redo != null) {
  1063. Gee.HashMap<string, Value?> ob = get_data(id);
  1064. if (ob.has_key(key) && ob[key] != null)
  1065. _undo_redo._undo.write_set_property_guid_action(Action.SET_PROPERTY_GUID, id, key, (Guid)ob[key]);
  1066. else
  1067. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1068. _undo_redo._redo.clear();
  1069. }
  1070. set_property_internal(1, id, key, val);
  1071. }
  1072. public void set_property_vector3(Guid id, string key, Vector3 val)
  1073. {
  1074. assert(has_object(id));
  1075. assert(is_valid_key(key));
  1076. assert(is_valid_value(val));
  1077. if (_undo_redo != null) {
  1078. Gee.HashMap<string, Value?> ob = get_data(id);
  1079. if (ob.has_key(key) && ob[key] != null)
  1080. _undo_redo._undo.write_set_property_vector3_action(Action.SET_PROPERTY_VECTOR3, id, key, (Vector3)ob[key]);
  1081. else
  1082. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1083. _undo_redo._redo.clear();
  1084. }
  1085. set_property_internal(1, id, key, val);
  1086. }
  1087. public void set_property_quaternion(Guid id, string key, Quaternion val)
  1088. {
  1089. assert(has_object(id));
  1090. assert(is_valid_key(key));
  1091. assert(is_valid_value(val));
  1092. if (_undo_redo != null) {
  1093. Gee.HashMap<string, Value?> ob = get_data(id);
  1094. if (ob.has_key(key) && ob[key] != null)
  1095. _undo_redo._undo.write_set_property_quaternion_action(Action.SET_PROPERTY_QUATERNION, id, key, (Quaternion)ob[key]);
  1096. else
  1097. _undo_redo._undo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1098. _undo_redo._redo.clear();
  1099. }
  1100. set_property_internal(1, id, key, val);
  1101. }
  1102. public void set_property(Guid id, string key, Value? val)
  1103. {
  1104. if (val == null)
  1105. set_property_null(id, key);
  1106. if (val.holds(typeof(bool)))
  1107. set_property_bool(id, key, (bool)val);
  1108. else if (val.holds(typeof(double)))
  1109. set_property_double(id, key, (double)val);
  1110. else if (val.holds(typeof(string)))
  1111. set_property_string(id, key, (string)val);
  1112. else if (val.holds(typeof(Guid)))
  1113. set_property_guid(id, key, (Guid)val);
  1114. else if (val.holds(typeof(Vector3)))
  1115. set_property_vector3(id, key, (Vector3)val);
  1116. else if (val.holds(typeof(Quaternion)))
  1117. set_property_quaternion(id, key, (Quaternion)val);
  1118. else
  1119. assert(false);
  1120. }
  1121. public void add_to_set(Guid id, string key, Guid item_id)
  1122. {
  1123. assert(has_object(id));
  1124. assert(is_valid_key(key));
  1125. assert(item_id != GUID_ZERO);
  1126. assert(has_object(item_id));
  1127. if (_undo_redo != null) {
  1128. _undo_redo._undo.write_remove_from_set_action(Action.REMOVE_FROM_SET, id, key, item_id);
  1129. _undo_redo._redo.clear();
  1130. }
  1131. add_to_set_internal(1, id, key, item_id);
  1132. }
  1133. public void remove_from_set(Guid id, string key, Guid item_id)
  1134. {
  1135. assert(has_object(id));
  1136. assert(is_valid_key(key));
  1137. assert(item_id != GUID_ZERO);
  1138. if (_undo_redo != null) {
  1139. _undo_redo._undo.write_add_to_set_action(Action.ADD_TO_SET, id, key, item_id);
  1140. _undo_redo._redo.clear();
  1141. }
  1142. remove_from_set_internal(1, id, key, item_id);
  1143. }
  1144. public bool has_object(Guid id)
  1145. {
  1146. return id == GUID_ZERO || _data.has_key(id);
  1147. }
  1148. public bool has_property(Guid id, string key)
  1149. {
  1150. return get_property(id, key) != null;
  1151. }
  1152. public Value? get_property(Guid id, string key, Value? val = null)
  1153. {
  1154. assert(has_object(id));
  1155. assert(is_valid_key(key));
  1156. Gee.HashMap<string, Value?> ob = get_data(id);
  1157. Value? value = (ob.has_key(key) ? ob[key] : val);
  1158. if (_debug_getters)
  1159. logi("get_property %s %s %s".printf(debug_string(id), key, debug_string(value)));
  1160. return value;
  1161. }
  1162. public bool get_property_bool(Guid id, string key, bool deffault = false)
  1163. {
  1164. return (bool)get_property(id, key, deffault);
  1165. }
  1166. public double get_property_double(Guid id, string key, double deffault = 0.0)
  1167. {
  1168. return (double)get_property(id, key, deffault);
  1169. }
  1170. public string get_property_string(Guid id, string key, string deffault = "")
  1171. {
  1172. return (string)get_property(id, key, deffault);
  1173. }
  1174. public Guid get_property_guid(Guid id, string key, Guid deffault = GUID_ZERO)
  1175. {
  1176. return (Guid)get_property(id, key, deffault);
  1177. }
  1178. public Vector3 get_property_vector3(Guid id, string key, Vector3 deffault = VECTOR3_ZERO)
  1179. {
  1180. return (Vector3)get_property(id, key, deffault);
  1181. }
  1182. public Quaternion get_property_quaternion(Guid id, string key, Quaternion deffault = QUATERNION_IDENTITY)
  1183. {
  1184. return (Quaternion)get_property(id, key, deffault);
  1185. }
  1186. public Gee.HashSet<Guid?> get_property_set(Guid id, string key, Gee.HashSet<Guid?> deffault)
  1187. {
  1188. assert(has_object(id));
  1189. assert(is_valid_key(key));
  1190. Gee.HashMap<string, Value?> ob = get_data(id);
  1191. Gee.HashSet<Guid?> value;
  1192. if (ob.has_key(key))
  1193. value = ob[key] as Gee.HashSet<Guid?>;
  1194. else
  1195. value = deffault;
  1196. if (_debug_getters)
  1197. logi("get_property %s %s %s".printf(debug_string(id), key, debug_string(value)));
  1198. return value;
  1199. }
  1200. public Gee.HashMap<string, Value?> get_object(Guid id)
  1201. {
  1202. return (Gee.HashMap<string, Value?>)get_data(GUID_ZERO)[id.to_string()];
  1203. }
  1204. public string[] get_keys(Guid id)
  1205. {
  1206. Gee.HashMap<string, Value?> data = get_data(id);
  1207. return data.keys.to_array();
  1208. }
  1209. public void add_restore_point(int id, Guid?[] data, uint32 flags = 0u)
  1210. {
  1211. if (_debug)
  1212. logi("add_restore_point %d, undo size = %u".printf(id, _undo_redo._undo.size()));
  1213. if (_undo_redo != null) {
  1214. _undo_redo._undo.write_restore_point(id, flags, data);
  1215. _undo_redo._redo.clear();
  1216. switch (id) {
  1217. case ActionType.CREATE_OBJECTS:
  1218. objects_created(data, flags);
  1219. break;
  1220. case ActionType.DESTROY_OBJECTS:
  1221. objects_destroyed(data, flags);
  1222. break;
  1223. case ActionType.CHANGE_OBJECTS:
  1224. objects_changed(data, flags);
  1225. break;
  1226. default:
  1227. logw("Unknown action type %d".printf(id));
  1228. break;
  1229. }
  1230. }
  1231. }
  1232. /// Duplicates the object specified by id and assign new_id to the duplicated object.
  1233. public void duplicate(Guid id, Guid new_id, Database? dest = null)
  1234. {
  1235. assert(id != GUID_ZERO);
  1236. assert(new_id != GUID_ZERO);
  1237. assert(id != new_id);
  1238. assert(has_object(id));
  1239. if (dest == null)
  1240. dest = this;
  1241. dest.create(new_id, object_type(id));
  1242. Gee.HashMap<string, Value?> ob = get_data(id);
  1243. string[] keys = ob.keys.to_array();
  1244. foreach (string key in keys) {
  1245. Value? val = ob[key];
  1246. if (val.holds(typeof(Gee.HashSet))) {
  1247. Gee.HashSet<Guid?> hs = (Gee.HashSet<Guid?>)val;
  1248. foreach (Guid j in hs) {
  1249. Guid x = Guid.new_guid();
  1250. duplicate(j, x, dest);
  1251. dest.add_to_set(new_id, key, x);
  1252. }
  1253. } else {
  1254. if (ob[key] == null)
  1255. dest.set_property_null(new_id, key);
  1256. else if (ob[key].holds(typeof(bool)))
  1257. dest.set_property_bool(new_id, key, (bool)ob[key]);
  1258. else if (ob[key].holds(typeof(double)))
  1259. dest.set_property_double(new_id, key, (double)ob[key]);
  1260. else if (ob[key].holds(typeof(string)))
  1261. dest.set_property_string(new_id, key, (string)ob[key]);
  1262. else if (ob[key].holds(typeof(Guid)))
  1263. dest.set_property_guid(new_id, key, (Guid)ob[key]);
  1264. else if (ob[key].holds(typeof(Vector3)))
  1265. dest.set_property_vector3(new_id, key, (Vector3)ob[key]);
  1266. else if (ob[key].holds(typeof(Quaternion)))
  1267. dest.set_property_quaternion(new_id, key, (Quaternion)ob[key]);
  1268. else
  1269. assert(false);
  1270. }
  1271. }
  1272. }
  1273. /// Copies the database to db under the given new_key.
  1274. public void copy_to(Database db, string new_key)
  1275. {
  1276. assert(db != null);
  1277. assert(is_valid_key(new_key));
  1278. copy_deep(db, GUID_ZERO, new_key);
  1279. }
  1280. public void copy_deep(Database db, Guid id, string new_key)
  1281. {
  1282. Gee.HashMap<string, Value?> ob = get_data(id);
  1283. string[] keys = ob.keys.to_array();
  1284. foreach (string key in keys) {
  1285. Value? value = ob[key];
  1286. if (value.holds(typeof(Gee.HashSet))) {
  1287. Gee.HashSet<Guid?> hs = (Gee.HashSet<Guid?>)value;
  1288. foreach (Guid j in hs) {
  1289. db.create(j, object_type(j));
  1290. copy_deep(db, j, "");
  1291. db.add_to_set(id, new_key + (new_key == "" ? "" : ".") + key, j);
  1292. }
  1293. } else {
  1294. if (!db.has_object(id))
  1295. db.create(id, object_type(id));
  1296. string kk = new_key + (new_key == "" ? "" : ".") + key;
  1297. if (ob[key] == null)
  1298. db.set_property_null(id, kk);
  1299. if (ob[key].holds(typeof(bool)))
  1300. db.set_property_bool(id, kk, (bool)ob[key]);
  1301. if (ob[key].holds(typeof(double)))
  1302. db.set_property_double(id, kk, (double)ob[key]);
  1303. if (ob[key].holds(typeof(string)))
  1304. db.set_property_string(id, kk, (string)ob[key]);
  1305. if (ob[key].holds(typeof(Guid)))
  1306. db.set_property_guid(id, kk, (Guid)ob[key]);
  1307. if (ob[key].holds(typeof(Vector3)))
  1308. db.set_property_vector3(id, kk, (Vector3)ob[key]);
  1309. if (ob[key].holds(typeof(Quaternion)))
  1310. db.set_property_quaternion(id, kk, (Quaternion)ob[key]);
  1311. }
  1312. }
  1313. }
  1314. // Tries to read a restore point @a rp from the @a stack and returns
  1315. // 0 if successful.
  1316. public int try_read_restore_point(ref RestorePoint rp, Stack stack)
  1317. {
  1318. if (stack.size() < sizeof(Action) + sizeof(RestorePointHeader))
  1319. return -1;
  1320. rp = stack.read_restore_point();
  1321. if (stack.size() < rp.header.size) {
  1322. // The restore point has been overwritten.
  1323. stack.clear();
  1324. return -1;
  1325. }
  1326. return 0;
  1327. }
  1328. // Un-does the last action and returns its ID, or -1 if there is no
  1329. // action to undo.
  1330. public int undo()
  1331. {
  1332. if (_undo_redo == null)
  1333. return -1;
  1334. RestorePoint rp = {};
  1335. if (try_read_restore_point(ref rp, _undo_redo._undo) != 0)
  1336. return -1;
  1337. undo_or_redo(_undo_redo._undo, _undo_redo._redo, rp.header.size);
  1338. switch (rp.header.id) {
  1339. case ActionType.CREATE_OBJECTS:
  1340. objects_destroyed(rp.data, 0u);
  1341. break;
  1342. case ActionType.DESTROY_OBJECTS:
  1343. objects_created(rp.data, 0u);
  1344. break;
  1345. case ActionType.CHANGE_OBJECTS:
  1346. objects_changed(rp.data, 0u);
  1347. break;
  1348. default:
  1349. logw("Unknown action type %u".printf(rp.header.id));
  1350. break;
  1351. }
  1352. _undo_redo._redo.write_restore_point(rp.header.id, rp.header.flags, rp.data);
  1353. return (int)rp.header.id;
  1354. }
  1355. // Re-does the last action and returns its ID, or -1 if there is no
  1356. // action to redo.
  1357. public int redo()
  1358. {
  1359. if (_undo_redo == null)
  1360. return -1;
  1361. RestorePoint rp = {};
  1362. if (try_read_restore_point(ref rp, _undo_redo._redo) != 0)
  1363. return -1;
  1364. undo_or_redo(_undo_redo._redo, _undo_redo._undo, rp.header.size);
  1365. switch (rp.header.id) {
  1366. case ActionType.CREATE_OBJECTS:
  1367. objects_created(rp.data, 0u);
  1368. break;
  1369. case ActionType.DESTROY_OBJECTS:
  1370. objects_destroyed(rp.data, 0u);
  1371. break;
  1372. case ActionType.CHANGE_OBJECTS:
  1373. objects_changed(rp.data, 0u);
  1374. break;
  1375. default:
  1376. logw("Unknown action type %u".printf(rp.header.id));
  1377. break;
  1378. }
  1379. _undo_redo._undo.write_restore_point(rp.header.id, rp.header.flags, rp.data);
  1380. return (int)rp.header.id;
  1381. }
  1382. public void undo_or_redo(Stack undo, Stack redo, uint32 restore_point_size)
  1383. {
  1384. assert(undo.size() >= restore_point_size);
  1385. int dir = undo == _undo_redo._undo ? -1 : 1;
  1386. // Read up to restore_point_size bytes.
  1387. uint32 undo_size_start = undo.size();
  1388. while (undo_size_start - undo.size() < restore_point_size) {
  1389. Action action = (Action)undo.read_uint32();
  1390. if (action == Action.CREATE) {
  1391. Guid id = undo.read_guid();
  1392. string obj_type = undo.read_string();
  1393. set_object_alive(id, true);
  1394. redo.write_destroy_action(Action.DESTROY, id, obj_type);
  1395. } else if (action == Action.DESTROY) {
  1396. Guid id = undo.read_guid();
  1397. string obj_type = undo.read_string();
  1398. set_object_alive(id, false);
  1399. redo.write_create_action(Action.CREATE, id, obj_type);
  1400. } else if (action == Action.SET_PROPERTY_NULL) {
  1401. Guid id = undo.read_guid();
  1402. string key = undo.read_string();
  1403. if (has_property(id, key)) {
  1404. if (get_data(id)[key].holds(typeof(bool)))
  1405. redo.write_set_property_bool_action(Action.SET_PROPERTY_BOOL, id, key, get_property_bool(id, key));
  1406. if (get_data(id)[key].holds(typeof(double)))
  1407. redo.write_set_property_double_action(Action.SET_PROPERTY_DOUBLE, id, key, get_property_double(id, key));
  1408. if (get_data(id)[key].holds(typeof(string)))
  1409. redo.write_set_property_string_action(Action.SET_PROPERTY_STRING, id, key, get_property_string(id, key));
  1410. if (get_data(id)[key].holds(typeof(Guid)))
  1411. redo.write_set_property_guid_action(Action.SET_PROPERTY_GUID, id, key, get_property_guid(id, key));
  1412. if (get_data(id)[key].holds(typeof(Vector3)))
  1413. redo.write_set_property_vector3_action(Action.SET_PROPERTY_VECTOR3, id, key, get_property_vector3(id, key));
  1414. if (get_data(id)[key].holds(typeof(Quaternion)))
  1415. redo.write_set_property_quaternion_action(Action.SET_PROPERTY_QUATERNION, id, key, get_property_quaternion(id, key));
  1416. } else {
  1417. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1418. }
  1419. set_property_internal(dir, id, key, null);
  1420. } else if (action == Action.SET_PROPERTY_BOOL) {
  1421. Guid id = undo.read_guid();
  1422. string key = undo.read_string();
  1423. bool val = undo.read_bool();
  1424. if (has_property(id, key))
  1425. redo.write_set_property_bool_action(Action.SET_PROPERTY_BOOL, id, key, get_property_bool(id, key));
  1426. else
  1427. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1428. set_property_internal(dir, id, key, val);
  1429. } else if (action == Action.SET_PROPERTY_DOUBLE) {
  1430. Guid id = undo.read_guid();
  1431. string key = undo.read_string();
  1432. double val = undo.read_double();
  1433. if (has_property(id, key))
  1434. redo.write_set_property_double_action(Action.SET_PROPERTY_DOUBLE, id, key, get_property_double(id, key));
  1435. else
  1436. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1437. set_property_internal(dir, id, key, val);
  1438. } else if (action == Action.SET_PROPERTY_STRING) {
  1439. Guid id = undo.read_guid();
  1440. string key = undo.read_string();
  1441. string val = undo.read_string();
  1442. if (has_property(id, key))
  1443. redo.write_set_property_string_action(Action.SET_PROPERTY_STRING, id, key, get_property_string(id, key));
  1444. else
  1445. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1446. set_property_internal(dir, id, key, val);
  1447. } else if (action == Action.SET_PROPERTY_GUID) {
  1448. Guid id = undo.read_guid();
  1449. string key = undo.read_string();
  1450. Guid val = undo.read_guid();
  1451. if (has_property(id, key))
  1452. redo.write_set_property_guid_action(Action.SET_PROPERTY_GUID, id, key, get_property_guid(id, key));
  1453. else
  1454. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1455. set_property_internal(dir, id, key, val);
  1456. } else if (action == Action.SET_PROPERTY_VECTOR3) {
  1457. Guid id = undo.read_guid();
  1458. string key = undo.read_string();
  1459. Vector3 val = undo.read_vector3();
  1460. if (has_property(id, key))
  1461. redo.write_set_property_vector3_action(Action.SET_PROPERTY_VECTOR3, id, key, get_property_vector3(id, key));
  1462. else
  1463. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1464. set_property_internal(dir, id, key, val);
  1465. } else if (action == Action.SET_PROPERTY_QUATERNION) {
  1466. Guid id = undo.read_guid();
  1467. string key = undo.read_string();
  1468. Quaternion val = undo.read_quaternion();
  1469. if (has_property(id, key))
  1470. redo.write_set_property_quaternion_action(Action.SET_PROPERTY_QUATERNION, id, key, get_property_quaternion(id, key));
  1471. else
  1472. redo.write_set_property_null_action(Action.SET_PROPERTY_NULL, id, key);
  1473. set_property_internal(dir, id, key, val);
  1474. } else if (action == Action.ADD_TO_SET) {
  1475. Guid id = undo.read_guid();
  1476. string key = undo.read_string();
  1477. Guid item_id = undo.read_guid();
  1478. redo.write_remove_from_set_action(Action.REMOVE_FROM_SET, id, key, item_id);
  1479. add_to_set_internal(dir, id, key, item_id);
  1480. } else if (action == Action.REMOVE_FROM_SET) {
  1481. Guid id = undo.read_guid();
  1482. string key = undo.read_string();
  1483. Guid item_id = undo.read_guid();
  1484. redo.write_add_to_set_action(Action.ADD_TO_SET, id, key, item_id);
  1485. remove_from_set_internal(dir, id, key, item_id);
  1486. }
  1487. }
  1488. }
  1489. // Creates a new object @a type with the specified @a properties and returns its ID.
  1490. public StringId64 create_object_type(string type
  1491. , PropertyDefinition[] properties
  1492. , double ui_order = 0.0
  1493. , ObjectTypeFlags flags = ObjectTypeFlags.NONE
  1494. , string? user_data = null
  1495. )
  1496. {
  1497. StringId64 type_hash = StringId64(type);
  1498. assert(!_object_definitions.has_key(type_hash));
  1499. assert(properties.length > 0);
  1500. ObjectTypeInfo info = {};
  1501. info.properties = { _property_definitions.length, _property_definitions.length + properties.length };
  1502. info.name = type;
  1503. info.ui_order = ui_order;
  1504. info.flags = flags;
  1505. info.user_data = user_data;
  1506. _object_definitions[type_hash] = info;
  1507. foreach (PropertyDefinition def in properties) {
  1508. // Generate labels if missing.
  1509. if (def.label == null) {
  1510. int ld = def.name.last_index_of_char('.');
  1511. string label = ld == -1 ? def.name : def.name.substring(ld + 1);
  1512. def.label = camel_case(label);
  1513. }
  1514. if (def.enum_labels.length == 0) {
  1515. string[] labels = new string[def.enum_values.length];
  1516. for (int i = 0; i < def.enum_values.length; ++i)
  1517. labels[i] = camel_case(def.enum_values[i]);
  1518. def.enum_labels = labels;
  1519. }
  1520. // Assign default/min/max values.
  1521. switch (def.type) {
  1522. case PropertyType.BOOL:
  1523. if (def.deffault == null)
  1524. def.deffault = false;
  1525. assert(def.deffault.holds(typeof(bool)));
  1526. break;
  1527. case PropertyType.DOUBLE:
  1528. if (def.deffault == null)
  1529. def.deffault = 0.0;
  1530. if (def.min == null)
  1531. def.min = double.MIN;
  1532. if (def.max == null)
  1533. def.max = double.MAX;
  1534. assert(def.deffault.holds(typeof(double)));
  1535. assert(def.min.holds(typeof(double)));
  1536. assert(def.max.holds(typeof(double)));
  1537. break;
  1538. case PropertyType.STRING:
  1539. if (def.deffault == null) {
  1540. if (def.enum_values.length > 0)
  1541. def.deffault = def.enum_values[0];
  1542. else
  1543. def.deffault = "";
  1544. }
  1545. assert(def.enum_property == null && def.enum_callback == null || def.enum_property != null && def.enum_callback != null && def.enum_values.length == 0);
  1546. assert(def.deffault.holds(typeof(string)));
  1547. break;
  1548. case PropertyType.VECTOR3:
  1549. if (def.deffault == null)
  1550. def.deffault = VECTOR3_ZERO;
  1551. if (def.min == null)
  1552. def.min = VECTOR3_MIN;
  1553. if (def.max == null)
  1554. def.max = VECTOR3_MAX;
  1555. assert(def.deffault.holds(typeof(Vector3)));
  1556. assert(def.min.holds(typeof(Vector3)));
  1557. assert(def.max.holds(typeof(Vector3)));
  1558. break;
  1559. case PropertyType.QUATERNION:
  1560. if (def.deffault == null)
  1561. def.deffault = QUATERNION_IDENTITY;
  1562. assert(def.deffault.holds(typeof(Quaternion)));
  1563. break;
  1564. case PropertyType.OBJECTS_SET:
  1565. break;
  1566. case PropertyType.OBJECT_NAME:
  1567. assert(def.resource_type != null);
  1568. assert(def.min == null);
  1569. assert(def.max == null);
  1570. assert(def.deffault == null || def.deffault.holds(typeof(string)));
  1571. break;
  1572. default:
  1573. assert(false);
  1574. break;
  1575. case PropertyType.OBJECT_REFERENCE:
  1576. def.deffault = GUID_ZERO;
  1577. assert(def.deffault.holds(typeof(Guid)));
  1578. assert(def.object_type._id != 0);
  1579. break;
  1580. }
  1581. _property_definitions += def;
  1582. }
  1583. object_type_added(info);
  1584. return type_hash;
  1585. }
  1586. // Returns the array of properties (i.e. its definition) of the object @a type.
  1587. public unowned PropertyDefinition[]? object_definition(StringId64 type)
  1588. {
  1589. if (!_object_definitions.has_key(type))
  1590. return null;
  1591. PropertiesSlice ps = _object_definitions[type].properties;
  1592. return _property_definitions[ps.start : ps.end];
  1593. }
  1594. // Returns the name of the object @id. If the object has no name set, it returns
  1595. // OBJECT_NAME_UNNAMED.
  1596. public string object_name(Guid id)
  1597. {
  1598. string name = get_property_string(id, "editor.name", OBJECT_NAME_UNNAMED);
  1599. if (name == OBJECT_NAME_UNNAMED)
  1600. return get_property_string(id, "name", OBJECT_NAME_UNNAMED);
  1601. return name;
  1602. }
  1603. // Sets the @a name of the object @a id.
  1604. public void set_object_name(Guid id, string name)
  1605. {
  1606. set_property_string(id, "editor.name", name);
  1607. }
  1608. // Returns whether the object @a type exists (i.e. has been created with create_object_type()).
  1609. public bool has_object_type(StringId64 type)
  1610. {
  1611. return _object_definitions.has_key(type);
  1612. }
  1613. public string object_type_name(StringId64 type)
  1614. {
  1615. return _object_definitions[type].name;
  1616. }
  1617. public uint object_type_flags(StringId64 type)
  1618. {
  1619. return _object_definitions[type].flags;
  1620. }
  1621. public ObjectTypeInfo object_type_info(StringId64 type)
  1622. {
  1623. return _object_definitions[type];
  1624. }
  1625. }
  1626. } /* namespace Crown */