database.vala 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369
  1. /*
  2. * Copyright (c) 2012-2021 Daniele Bartolini et al.
  3. * License: https://github.com/dbartolini/crown/blob/master/LICENSE
  4. */
  5. using Gee;
  6. namespace Crown
  7. {
  8. public class Database
  9. {
  10. private static bool _debug = false;
  11. private static bool _debug_getters = false;
  12. private enum Action
  13. {
  14. CREATE,
  15. DESTROY,
  16. SET_PROPERTY_NULL,
  17. SET_PROPERTY_BOOL,
  18. SET_PROPERTY_DOUBLE,
  19. SET_PROPERTY_STRING,
  20. SET_PROPERTY_GUID,
  21. SET_PROPERTY_VECTOR3,
  22. SET_PROPERTY_QUATERNION,
  23. ADD_TO_SET,
  24. REMOVE_FROM_SET,
  25. RESTORE_POINT
  26. }
  27. private struct RestorePoint
  28. {
  29. public int id;
  30. public uint32 size;
  31. public Guid[] data;
  32. }
  33. private class Stack
  34. {
  35. private uint8[] _data;
  36. private uint32 _read;
  37. public Stack()
  38. {
  39. _data = new uint8[1024*1024];
  40. _read = 0;
  41. }
  42. public void clear()
  43. {
  44. _read = 0;
  45. }
  46. public uint32 size()
  47. {
  48. return _read;
  49. }
  50. public void write_data(void* data, ulong len)
  51. {
  52. uint8* buf = (uint8*)data;
  53. for (ulong i = 0; i < len; ++i, ++_read)
  54. _data[_read] = buf[i];
  55. }
  56. public void write_bool(bool a)
  57. {
  58. write_data(&a, sizeof(bool));
  59. }
  60. public void write_int(int a)
  61. {
  62. write_data(&a, sizeof(int));
  63. }
  64. public void write_uint32(uint32 a)
  65. {
  66. write_data(&a, sizeof(uint32));
  67. }
  68. public void write_double(double a)
  69. {
  70. write_data(&a, sizeof(double));
  71. }
  72. public void write_string(string str)
  73. {
  74. uint32 len = str.length;
  75. write_data(&str.data[0], len);
  76. write_data(&len, sizeof(uint32));
  77. }
  78. public void write_guid(Guid a)
  79. {
  80. write_data(&a, sizeof(Guid));
  81. }
  82. public void write_vector3(Vector3 a)
  83. {
  84. write_data(&a, sizeof(Vector3));
  85. }
  86. public void write_quaternion(Quaternion a)
  87. {
  88. write_data(&a, sizeof(Quaternion));
  89. }
  90. public void write_action(Action t)
  91. {
  92. write_uint32((uint32)t);
  93. }
  94. public Action read_action()
  95. {
  96. _read -= (uint32)sizeof(uint32);
  97. uint32 a = *(uint32*)(&_data[_read]);
  98. return (Action)a;
  99. }
  100. public bool read_bool()
  101. {
  102. _read -= (uint32)sizeof(bool);
  103. bool a = *(bool*)(&_data[_read]);
  104. return a;
  105. }
  106. public int read_int()
  107. {
  108. _read -= (uint32)sizeof(int);
  109. int a = *(int*)(&_data[_read]);
  110. return a;
  111. }
  112. public uint32 read_uint32()
  113. {
  114. _read -= (uint32)sizeof(uint32);
  115. uint32 a = *(uint32*)(&_data[_read]);
  116. return a;
  117. }
  118. public double read_double()
  119. {
  120. _read -= (uint32)sizeof(double);
  121. double a = *(double*)(&_data[_read]);
  122. return a;
  123. }
  124. public Guid read_guid()
  125. {
  126. _read -= (uint32)sizeof(Guid);
  127. Guid a = *(Guid*)(&_data[_read]);
  128. return a;
  129. }
  130. public Vector3 read_vector3()
  131. {
  132. _read -= (uint32)sizeof(Vector3);
  133. Vector3 a = *(Vector3*)(&_data[_read]);
  134. return a;
  135. }
  136. public Quaternion read_quaternion()
  137. {
  138. _read -= (uint32)sizeof(Quaternion);
  139. Quaternion a = *(Quaternion*)(&_data[_read]);
  140. return a;
  141. }
  142. public string read_string()
  143. {
  144. _read -= (uint32)sizeof(uint32);
  145. uint32 len = *(uint32*)(&_data[_read]);
  146. _read -= len;
  147. uint8[] str = new uint8[len + 1];
  148. for (uint32 i = 0; i < len; ++i)
  149. str[i] = *(uint8*)(&_data[_read + i]);
  150. str[len] = '\0';
  151. return (string)str;
  152. }
  153. public void write_create_action(Guid id)
  154. {
  155. write_guid(id);
  156. write_action(Action.CREATE);
  157. }
  158. public void write_destroy_action(Guid id)
  159. {
  160. write_guid(id);
  161. write_action(Action.DESTROY);
  162. }
  163. public void write_set_property_null_action(Guid id, string key)
  164. {
  165. // No value to push
  166. write_string(key);
  167. write_guid(id);
  168. write_action(Action.SET_PROPERTY_NULL);
  169. }
  170. public void write_set_property_bool_action(Guid id, string key, bool val)
  171. {
  172. write_bool(val);
  173. write_string(key);
  174. write_guid(id);
  175. write_action(Action.SET_PROPERTY_BOOL);
  176. }
  177. public void write_set_property_double_action(Guid id, string key, double val)
  178. {
  179. write_double(val);
  180. write_string(key);
  181. write_guid(id);
  182. write_action(Action.SET_PROPERTY_DOUBLE);
  183. }
  184. public void write_set_property_string_action(Guid id, string key, string val)
  185. {
  186. write_string(val);
  187. write_string(key);
  188. write_guid(id);
  189. write_action(Action.SET_PROPERTY_STRING);
  190. }
  191. public void write_set_property_guid_action(Guid id, string key, Guid val)
  192. {
  193. write_guid(val);
  194. write_string(key);
  195. write_guid(id);
  196. write_action(Action.SET_PROPERTY_GUID);
  197. }
  198. public void write_set_property_vector3_action(Guid id, string key, Vector3 val)
  199. {
  200. write_vector3(val);
  201. write_string(key);
  202. write_guid(id);
  203. write_action(Action.SET_PROPERTY_VECTOR3);
  204. }
  205. public void write_set_property_quaternion_action(Guid id, string key, Quaternion val)
  206. {
  207. write_quaternion(val);
  208. write_string(key);
  209. write_guid(id);
  210. write_action(Action.SET_PROPERTY_QUATERNION);
  211. }
  212. public void write_add_to_set_action(Guid id, string key, Guid item_id)
  213. {
  214. write_guid(item_id);
  215. write_string(key);
  216. write_guid(id);
  217. write_action(Action.ADD_TO_SET);
  218. }
  219. public void write_remove_from_set_action(Guid id, string key, Guid item_id)
  220. {
  221. write_guid(item_id);
  222. write_string(key);
  223. write_guid(id);
  224. write_action(Action.REMOVE_FROM_SET);
  225. }
  226. public void write_restore_point(int id, uint32 size, Guid[] data)
  227. {
  228. uint32 num_guids = data.length;
  229. for (uint32 i = 0; i < num_guids; ++i)
  230. write_guid(data[i]);
  231. write_uint32(num_guids);
  232. write_uint32(size);
  233. write_int(id);
  234. write_action(Action.RESTORE_POINT);
  235. }
  236. public uint32 peek_type()
  237. {
  238. return *(uint32*)(&_data[_read - (uint32)sizeof(uint32)]);
  239. }
  240. public RestorePoint read_restore_point()
  241. {
  242. Action t = read_action();
  243. assert(t == Action.RESTORE_POINT);
  244. int id = read_int();
  245. uint32 size = read_uint32();
  246. uint32 num_guids = read_uint32();
  247. Guid[] ids = new Guid[num_guids];
  248. for (uint32 i = 0; i < num_guids; ++i)
  249. ids[i] = read_guid();
  250. return { id, size, ids };
  251. }
  252. }
  253. // Data
  254. private HashMap<Guid?, HashMap<string, Value?>> _data;
  255. private Stack _undo;
  256. private Stack _redo;
  257. private Stack _undo_points;
  258. private Stack _redo_points;
  259. // The number of changes to the database since the last successful state
  260. // synchronization (load(), save() etc.). If it is less than 0, the changes
  261. // came from undo(), otherwise they came from redo() or from regular calls to
  262. // create(), destroy(), set_*() etc. A value of 0 means there were no changes.
  263. public int _distance_from_last_sync;
  264. // Signals
  265. public signal void key_changed(Guid id, string key);
  266. public signal void object_created(Guid id);
  267. public signal void object_destroyed(Guid id);
  268. public signal void undo_redo(bool undo, int id, Guid[] data);
  269. public Database()
  270. {
  271. _data = new HashMap<Guid?, HashMap<string, Value?>>(Guid.hash_func, Guid.equal_func);
  272. _undo = new Stack();
  273. _redo = new Stack();
  274. _undo_points = new Stack();
  275. _redo_points = new Stack();
  276. reset();
  277. }
  278. /// Resets database to clean state.
  279. public void reset()
  280. {
  281. _data.clear();
  282. _undo.clear();
  283. _redo.clear();
  284. _undo_points.clear();
  285. _redo_points.clear();
  286. _distance_from_last_sync = 0;
  287. // This is a special field which stores all objects
  288. _data[GUID_ZERO] = new HashMap<string, Value?>();
  289. }
  290. /// Returns whether the database has been changed since last call to Save().
  291. public bool changed()
  292. {
  293. return _distance_from_last_sync != 0;
  294. }
  295. /// Saves database to path without marking it as not changed.
  296. public void dump(string path, Guid id)
  297. {
  298. Hashtable json = encode(id);
  299. SJSON.save(json, path);
  300. }
  301. /// Saves database to path.
  302. public void save(string path, Guid id)
  303. {
  304. dump(path, id);
  305. _distance_from_last_sync = 0;
  306. }
  307. // See: load_more_from_path().
  308. public int load_more_from_file(out Guid object_id, FileStream? fs, string resource_path)
  309. {
  310. Hashtable json = SJSON.load_from_file(fs);
  311. if (json.has_key("id"))
  312. object_id = Guid.parse((string)json["id"]);
  313. else
  314. object_id = Guid.new_guid();
  315. create_internal(0, object_id);
  316. set_object_type(object_id, resource_type(resource_path));
  317. decode_object(object_id, "", json);
  318. // Create a mapping between the path and the object it has been loaded into.
  319. set_property_internal(0, GUID_ZERO, resource_path, object_id);
  320. return 0;
  321. }
  322. // Loads the database with the object stored at @a path, without resetting the
  323. // database. This makes it possible to load multiple objects from distinct
  324. // paths in the same database. @a resource_path is used as a key in the
  325. // database to refer to the object that has been loaded. This is useful when
  326. // you do not have the object ID but only its path, as it is often the case
  327. // since resources use paths and not IDs to reference each other.
  328. public int load_more_from_path(out Guid object_id, string path, string resource_path)
  329. {
  330. object_id = GUID_ZERO;
  331. FileStream fs = FileStream.open(path, "rb");
  332. if (fs == null)
  333. return 1;
  334. return load_more_from_file(out object_id, fs, resource_path);
  335. }
  336. /// Loads the database with the object stored at @a path.
  337. public int load_from_file(out Guid object_id, FileStream fs, string resource_path)
  338. {
  339. reset();
  340. return load_more_from_file(out object_id, fs, resource_path);
  341. }
  342. /// Loads the database with the object stored at @a path.
  343. public int load_from_path(out Guid object_id, string path, string resource_path)
  344. {
  345. reset();
  346. return load_more_from_path(out object_id, path, resource_path);
  347. }
  348. /// Encodes the object @a id into SJSON object.
  349. private Hashtable encode(Guid id)
  350. {
  351. return encode_object(id, get_data(id));
  352. }
  353. private static bool is_valid_value(Value? value)
  354. {
  355. return value == null
  356. || value.holds(typeof(bool))
  357. || value.holds(typeof(double))
  358. || value.holds(typeof(string))
  359. || value.holds(typeof(Guid))
  360. || value.holds(typeof(Vector3))
  361. || value.holds(typeof(Quaternion))
  362. ;
  363. }
  364. private static bool is_valid_key(string key)
  365. {
  366. return key.length > 0
  367. && !key.has_prefix(".")
  368. && !key.has_suffix(".")
  369. ;
  370. }
  371. private static string value_to_string(Value? value)
  372. {
  373. if (value == null)
  374. return "null";
  375. if (value.holds(typeof(bool)))
  376. return ((bool)value).to_string();
  377. if (value.holds(typeof(double)))
  378. return ((double)value).to_string();
  379. if (value.holds(typeof(string)))
  380. return ((string)value).to_string();
  381. if (value.holds(typeof(Guid)))
  382. return ((Guid)value).to_string();
  383. if (value.holds(typeof(Vector3)))
  384. return ((Vector3)value).to_string();
  385. if (value.holds(typeof(Quaternion)))
  386. return ((Quaternion)value).to_string();
  387. if (value.holds(typeof(HashSet)))
  388. return "Set<Guid>";
  389. return "<invalid>";
  390. }
  391. private void decode_object(Guid id, string db_key, Hashtable json)
  392. {
  393. string old_db = db_key;
  394. string k = db_key;
  395. if (k == "" && json.has_key("type"))
  396. {
  397. // The "type" key defines object type only if it appears
  398. // in the root of a JSON object (k == "").
  399. if (!has_property(id, "type"))
  400. set_object_type(id, (string)json["type"]);
  401. }
  402. string[] keys = json.keys.to_array();
  403. foreach (string key in keys)
  404. {
  405. if (key == "id")
  406. continue;
  407. Value? val = json[key];
  408. k += k == "" ? key : ("." + key);
  409. if (val.holds(typeof(Hashtable)))
  410. {
  411. Hashtable ht = (Hashtable)val;
  412. decode_object(id, k, ht);
  413. }
  414. else if (val.holds(typeof(ArrayList)))
  415. {
  416. ArrayList<Value?> arr = (ArrayList<Value?>)val;
  417. if (arr.size > 0 && arr[0].holds(typeof(double)))
  418. set_property_internal(0, id, k, decode_value(val));
  419. else
  420. decode_set(id, key, arr);
  421. }
  422. else
  423. {
  424. set_property_internal(0, id, k, decode_value(val));
  425. }
  426. k = old_db;
  427. }
  428. }
  429. private void decode_set(Guid owner_id, string key, ArrayList<Value?> json)
  430. {
  431. // Set should be created even if it is empty.
  432. create_empty_set(0, owner_id, key);
  433. for (int i = 0; i < json.size; ++i)
  434. {
  435. Hashtable obj = (Hashtable)json[i];
  436. Guid obj_id = Guid.parse((string)obj["id"]);
  437. create_internal(0, obj_id);
  438. decode_object(obj_id, "", obj);
  439. add_to_set_internal(0, owner_id, key, obj_id);
  440. }
  441. }
  442. private Value? decode_value(Value? value)
  443. {
  444. if (value.holds(typeof(ArrayList)))
  445. {
  446. ArrayList<Value?> al = (ArrayList<Value?>)value;
  447. if (al.size == 3)
  448. return Vector3((double)al[0], (double)al[1], (double)al[2]);
  449. else if (al.size == 4)
  450. return Quaternion((double)al[0], (double)al[1], (double)al[2], (double)al[3]);
  451. else
  452. assert(false);
  453. }
  454. else if (value.holds(typeof(string)))
  455. {
  456. Guid id;
  457. if (Guid.try_parse((string)value, out id))
  458. return id;
  459. return value;
  460. }
  461. else if (value == null || value.holds(typeof(bool)) || value.holds(typeof(double)))
  462. {
  463. return value;
  464. }
  465. else
  466. {
  467. assert(false);
  468. }
  469. return null;
  470. }
  471. private Hashtable encode_object(Guid id, HashMap<string, Value?> db)
  472. {
  473. Hashtable obj = new Hashtable();
  474. if (id != GUID_ZERO)
  475. obj["id"] = id.to_string();
  476. string[] keys = db.keys.to_array();
  477. foreach (string key in keys)
  478. {
  479. // Since null-key is equivalent to non-existent key, skip serialization.
  480. if (db[key] == null)
  481. continue;
  482. string[] foo = key.split(".");
  483. Hashtable x = obj;
  484. if (foo.length > 1)
  485. {
  486. for (int i = 0; i < foo.length - 1; ++i)
  487. {
  488. string f = foo[i];
  489. if (x.has_key(f))
  490. {
  491. x = (Hashtable)x[f];
  492. continue;
  493. }
  494. Hashtable y = new Hashtable();
  495. x.set(f, y);
  496. x = y;
  497. }
  498. }
  499. x.set(foo[foo.length-1], encode_value(db[key]));
  500. }
  501. return obj;
  502. }
  503. private Value? encode_value(Value? value)
  504. {
  505. assert(is_valid_value(value) || value.holds(typeof(HashSet)));
  506. if (value.holds(typeof(Vector3)))
  507. {
  508. Vector3 v = (Vector3)value;
  509. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  510. arr.add(v.x);
  511. arr.add(v.y);
  512. arr.add(v.z);
  513. return arr;
  514. }
  515. else if (value.holds(typeof(Quaternion)))
  516. {
  517. Quaternion q = (Quaternion)value;
  518. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  519. arr.add(q.x);
  520. arr.add(q.y);
  521. arr.add(q.z);
  522. arr.add(q.w);
  523. return arr;
  524. }
  525. else if (value.holds(typeof(Guid)))
  526. {
  527. Guid id = (Guid)value;
  528. return id.to_string();
  529. }
  530. else if (value.holds(typeof(HashSet)))
  531. {
  532. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  533. ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
  534. foreach (Guid id in hs)
  535. {
  536. arr.add(encode_object(id, get_data(id)));
  537. }
  538. return arr;
  539. }
  540. else
  541. {
  542. return value;
  543. }
  544. }
  545. private HashMap<string, Value?> get_data(Guid id)
  546. {
  547. assert(has_object(id));
  548. return _data[id];
  549. }
  550. private void create_internal(int dir, Guid id)
  551. {
  552. assert(id != GUID_ZERO);
  553. if (_debug)
  554. logi("create %s".printf(id.to_string()));
  555. _data[id] = new HashMap<string, Value?>();
  556. _distance_from_last_sync += dir;
  557. object_created(id);
  558. }
  559. private void destroy_internal(int dir, Guid id)
  560. {
  561. assert(id != GUID_ZERO);
  562. assert(has_object(id));
  563. if (_debug)
  564. logi("destroy %s".printf(id.to_string()));
  565. object_destroyed(id);
  566. _distance_from_last_sync += dir;
  567. _data.unset(id);
  568. }
  569. private void set_property_internal(int dir, Guid id, string key, Value? value)
  570. {
  571. assert(has_object(id));
  572. assert(is_valid_key(key));
  573. assert(is_valid_value(value));
  574. if (_debug)
  575. logi("set_property %s %s %s".printf(id.to_string(), key, (value == null) ? "null" : value_to_string(value)));
  576. HashMap<string, Value?> ob = get_data(id);
  577. ob[key] = value;
  578. _distance_from_last_sync += dir;
  579. key_changed(id, key);
  580. }
  581. private void create_empty_set(int dir, Guid id, string key)
  582. {
  583. assert(has_object(id));
  584. assert(is_valid_key(key));
  585. HashMap<string, Value?> ob = get_data(id);
  586. assert(!ob.has_key(key));
  587. ob[key] = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  588. }
  589. private void add_to_set_internal(int dir, Guid id, string key, Guid item_id)
  590. {
  591. assert(has_object(id));
  592. assert(is_valid_key(key));
  593. assert(item_id != GUID_ZERO);
  594. assert(has_object(item_id));
  595. if (_debug)
  596. logi("add_to_set %s %s %s".printf(id.to_string(), key, item_id.to_string()));
  597. HashMap<string, Value?> ob = get_data(id);
  598. if (!ob.has_key(key))
  599. {
  600. HashSet<Guid?> hs = new HashSet<Guid?>(Guid.hash_func, Guid.equal_func);
  601. hs.add(item_id);
  602. ob[key] = hs;
  603. }
  604. else
  605. {
  606. ((HashSet<Guid?>)ob[key]).add(item_id);
  607. }
  608. _distance_from_last_sync += dir;
  609. key_changed(id, key);
  610. }
  611. private void remove_from_set_internal(int dir, Guid id, string key, Guid item_id)
  612. {
  613. assert(has_object(id));
  614. assert(is_valid_key(key));
  615. assert(item_id != GUID_ZERO);
  616. if (_debug)
  617. logi("remove_from_set %s %s %s".printf(id.to_string(), key, item_id.to_string()));
  618. HashMap<string, Value?> ob = get_data(id);
  619. ((HashSet<Guid?>)ob[key]).remove(item_id);
  620. _distance_from_last_sync += dir;
  621. key_changed(id, key);
  622. }
  623. // Returns the type of the object @a id.
  624. public string object_type(Guid id)
  625. {
  626. assert(has_object(id));
  627. return (string)get_data(id)["type"];
  628. }
  629. // Sets the @a type of the object @a id.
  630. // This is called automatically when loading data or when new objects are created via create().
  631. // It can occasionally be called manually after loading legacy data with no type information
  632. // stored inside objects.
  633. public void set_object_type(Guid id, string type)
  634. {
  635. assert(has_object(id));
  636. get_data(id)["type"] = type;
  637. }
  638. public void create(Guid id, string type)
  639. {
  640. assert(id != GUID_ZERO);
  641. assert(!has_object(id));
  642. _undo.write_destroy_action(id);
  643. _redo.clear();
  644. _redo_points.clear();
  645. create_internal(1, id);
  646. set_object_type(id, type);
  647. object_created(id);
  648. }
  649. public void destroy(Guid id)
  650. {
  651. assert(id != GUID_ZERO);
  652. assert(has_object(id));
  653. HashMap<string, Value?> o = get_data(id);
  654. string[] keys = o.keys.to_array();
  655. foreach (string key in keys)
  656. {
  657. Value? value = o[key];
  658. if (value.holds(typeof(HashSet)))
  659. {
  660. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  661. Guid?[] ids = hs.to_array();
  662. foreach (Guid item_id in ids)
  663. {
  664. remove_from_set(id, key, item_id);
  665. destroy(item_id);
  666. }
  667. }
  668. else
  669. {
  670. set_property_null(id, key);
  671. }
  672. }
  673. _undo.write_create_action(id);
  674. _redo.clear();
  675. _redo_points.clear();
  676. destroy_internal(1, id);
  677. }
  678. public void set_property_null(Guid id, string key)
  679. {
  680. assert(has_object(id));
  681. assert(is_valid_key(key));
  682. assert(is_valid_value(null));
  683. HashMap<string, Value?> ob = get_data(id);
  684. if (ob.has_key(key) && ob[key] != null)
  685. {
  686. if (ob[key].holds(typeof(bool)))
  687. _undo.write_set_property_bool_action(id, key, (bool)ob[key]);
  688. if (ob[key].holds(typeof(double)))
  689. _undo.write_set_property_double_action(id, key, (double)ob[key]);
  690. if (ob[key].holds(typeof(string)))
  691. _undo.write_set_property_string_action(id, key, (string)ob[key]);
  692. if (ob[key].holds(typeof(Guid)))
  693. _undo.write_set_property_guid_action(id, key, (Guid)ob[key]);
  694. if (ob[key].holds(typeof(Vector3)))
  695. _undo.write_set_property_vector3_action(id, key, (Vector3)ob[key]);
  696. if (ob[key].holds(typeof(Quaternion)))
  697. _undo.write_set_property_quaternion_action(id, key, (Quaternion)ob[key]);
  698. }
  699. else
  700. {
  701. _undo.write_set_property_null_action(id, key);
  702. }
  703. _redo.clear();
  704. _redo_points.clear();
  705. set_property_internal(1, id, key, null);
  706. }
  707. public void set_property_bool(Guid id, string key, bool val)
  708. {
  709. assert(has_object(id));
  710. assert(is_valid_key(key));
  711. assert(is_valid_value(val));
  712. HashMap<string, Value?> ob = get_data(id);
  713. if (ob.has_key(key) && ob[key] != null)
  714. _undo.write_set_property_bool_action(id, key, (bool)ob[key]);
  715. else
  716. _undo.write_set_property_null_action(id, key);
  717. _redo.clear();
  718. _redo_points.clear();
  719. set_property_internal(1, id, key, val);
  720. }
  721. public void set_property_double(Guid id, string key, double val)
  722. {
  723. assert(has_object(id));
  724. assert(is_valid_key(key));
  725. assert(is_valid_value(val));
  726. HashMap<string, Value?> ob = get_data(id);
  727. if (ob.has_key(key) && ob[key] != null)
  728. _undo.write_set_property_double_action(id, key, (double)ob[key]);
  729. else
  730. _undo.write_set_property_null_action(id, key);
  731. _redo.clear();
  732. _redo_points.clear();
  733. set_property_internal(1, id, key, val);
  734. }
  735. public void set_property_string(Guid id, string key, string val)
  736. {
  737. assert(has_object(id));
  738. assert(is_valid_key(key));
  739. assert(is_valid_value(val));
  740. HashMap<string, Value?> ob = get_data(id);
  741. if (ob.has_key(key) && ob[key] != null)
  742. _undo.write_set_property_string_action(id, key, (string)ob[key]);
  743. else
  744. _undo.write_set_property_null_action(id, key);
  745. _redo.clear();
  746. _redo_points.clear();
  747. set_property_internal(1, id, key, val);
  748. }
  749. public void set_property_guid(Guid id, string key, Guid val)
  750. {
  751. assert(has_object(id));
  752. assert(is_valid_key(key));
  753. assert(is_valid_value(val));
  754. HashMap<string, Value?> ob = get_data(id);
  755. if (ob.has_key(key) && ob[key] != null)
  756. _undo.write_set_property_guid_action(id, key, (Guid)ob[key]);
  757. else
  758. _undo.write_set_property_null_action(id, key);
  759. _redo.clear();
  760. _redo_points.clear();
  761. set_property_internal(1, id, key, val);
  762. }
  763. public void set_property_vector3(Guid id, string key, Vector3 val)
  764. {
  765. assert(has_object(id));
  766. assert(is_valid_key(key));
  767. assert(is_valid_value(val));
  768. HashMap<string, Value?> ob = get_data(id);
  769. if (ob.has_key(key) && ob[key] != null)
  770. _undo.write_set_property_vector3_action(id, key, (Vector3)ob[key]);
  771. else
  772. _undo.write_set_property_null_action(id, key);
  773. _redo.clear();
  774. _redo_points.clear();
  775. set_property_internal(1, id, key, val);
  776. }
  777. public void set_property_quaternion(Guid id, string key, Quaternion val)
  778. {
  779. assert(has_object(id));
  780. assert(is_valid_key(key));
  781. assert(is_valid_value(val));
  782. HashMap<string, Value?> ob = get_data(id);
  783. if (ob.has_key(key) && ob[key] != null)
  784. _undo.write_set_property_quaternion_action(id, key, (Quaternion)ob[key]);
  785. else
  786. _undo.write_set_property_null_action(id, key);
  787. _redo.clear();
  788. _redo_points.clear();
  789. set_property_internal(1, id, key, val);
  790. }
  791. public void add_to_set(Guid id, string key, Guid item_id)
  792. {
  793. assert(has_object(id));
  794. assert(is_valid_key(key));
  795. assert(item_id != GUID_ZERO);
  796. assert(has_object(item_id));
  797. _undo.write_remove_from_set_action(id, key, item_id);
  798. _redo.clear();
  799. _redo_points.clear();
  800. add_to_set_internal(1, id, key, item_id);
  801. }
  802. public void remove_from_set(Guid id, string key, Guid item_id)
  803. {
  804. assert(has_object(id));
  805. assert(is_valid_key(key));
  806. assert(item_id != GUID_ZERO);
  807. _undo.write_add_to_set_action(id, key, item_id);
  808. _redo.clear();
  809. _redo_points.clear();
  810. remove_from_set_internal(1, id, key, item_id);
  811. }
  812. public bool has_object(Guid id)
  813. {
  814. return id == GUID_ZERO || _data.has_key(id);
  815. }
  816. public bool has_property(Guid id, string key)
  817. {
  818. return get_property(id, key) != null;
  819. }
  820. public Value? get_property(Guid id, string key)
  821. {
  822. assert(has_object(id));
  823. assert(is_valid_key(key));
  824. HashMap<string, Value?> ob = get_data(id);
  825. Value? value = (ob.has_key(key) ? ob[key] : null);
  826. if (_debug_getters)
  827. logi("get_property %s %s %s".printf(id.to_string(), key, (value == null) ? "null" : value_to_string(value)));
  828. return value;
  829. }
  830. public bool get_property_bool(Guid id, string key)
  831. {
  832. return (bool)get_property(id, key);
  833. }
  834. public double get_property_double(Guid id, string key)
  835. {
  836. return (double)get_property(id, key);
  837. }
  838. public string get_property_string(Guid id, string key)
  839. {
  840. return (string)get_property(id, key);
  841. }
  842. public Guid get_property_guid(Guid id, string key)
  843. {
  844. return (Guid)get_property(id, key);
  845. }
  846. public Vector3 get_property_vector3(Guid id, string key)
  847. {
  848. return (Vector3)get_property(id, key);
  849. }
  850. public Quaternion get_property_quaternion(Guid id, string key)
  851. {
  852. return (Quaternion)get_property(id, key);
  853. }
  854. public HashSet<Guid?> get_property_set(Guid id, string key, HashSet<Guid?> deffault)
  855. {
  856. assert(has_object(id));
  857. assert(is_valid_key(key));
  858. HashMap<string, Value?> ob = get_data(id);
  859. HashSet<Guid?> value;
  860. if (ob.has_key(key))
  861. value = ob[key] as HashSet<Guid?>;
  862. else
  863. value = deffault;
  864. if (_debug_getters)
  865. logi("get_property %s %s %s".printf(id.to_string(), key, (value == null) ? "null" : value_to_string(value)));
  866. return value;
  867. }
  868. public HashMap<string, Value?> get_object(Guid id)
  869. {
  870. return (HashMap<string, Value?>)get_data(GUID_ZERO)[id.to_string()];
  871. }
  872. public string[] get_keys(Guid id)
  873. {
  874. HashMap<string, Value?> data = get_data(id);
  875. return data.keys.to_array();
  876. }
  877. public void add_restore_point(int id, Guid[] data)
  878. {
  879. if (_debug)
  880. logi("add_restore_point %d, undo size = %u".printf(id, _undo.size()));
  881. _undo_points.write_restore_point(id, _undo.size(), data);
  882. _redo.clear();
  883. _redo_points.clear();
  884. }
  885. /// Duplicates the object specified by id and assign new_id to the duplicated object.
  886. public void duplicate(Guid id, Guid new_id)
  887. {
  888. assert(id != GUID_ZERO);
  889. assert(new_id != GUID_ZERO);
  890. assert(id != new_id);
  891. assert(has_object(id));
  892. create(new_id, object_type(id));
  893. HashMap<string, Value?> ob = get_data(id);
  894. string[] keys = ob.keys.to_array();
  895. foreach (string key in keys)
  896. {
  897. Value? val = ob[key];
  898. if (val.holds(typeof(HashSet)))
  899. {
  900. HashSet<Guid?> hs = (HashSet<Guid?>)val;
  901. foreach (Guid j in hs)
  902. {
  903. Guid x = Guid.new_guid();
  904. duplicate(j, x);
  905. add_to_set(new_id, key, x);
  906. }
  907. }
  908. else
  909. {
  910. if (ob[key] == null)
  911. set_property_null(new_id, key);
  912. if (ob[key].holds(typeof(bool)))
  913. set_property_bool(new_id, key, (bool)ob[key]);
  914. if (ob[key].holds(typeof(double)))
  915. set_property_double(new_id, key, (double)ob[key]);
  916. if (ob[key].holds(typeof(string)))
  917. set_property_string(new_id, key, (string)ob[key]);
  918. if (ob[key].holds(typeof(Guid)))
  919. set_property_guid(new_id, key, (Guid)ob[key]);
  920. if (ob[key].holds(typeof(Vector3)))
  921. set_property_vector3(new_id, key, (Vector3)ob[key]);
  922. if (ob[key].holds(typeof(Quaternion)))
  923. set_property_quaternion(new_id, key, (Quaternion)ob[key]);
  924. }
  925. }
  926. }
  927. /// Copies the database to db under the given new_key.
  928. public void copy_to(Database db, string new_key)
  929. {
  930. assert(db != null);
  931. assert(is_valid_key(new_key));
  932. copy_deep(db, GUID_ZERO, new_key);
  933. }
  934. public void copy_deep(Database db, Guid id, string new_key)
  935. {
  936. HashMap<string, Value?> ob = get_data(id);
  937. string[] keys = ob.keys.to_array();
  938. foreach (string key in keys)
  939. {
  940. Value? value = ob[key];
  941. if (value.holds(typeof(HashSet)))
  942. {
  943. HashSet<Guid?> hs = (HashSet<Guid?>)value;
  944. foreach (Guid j in hs)
  945. {
  946. db.create(j, object_type(j));
  947. copy_deep(db, j, "");
  948. db.add_to_set(id, new_key + (new_key == "" ? "" : ".") + key, j);
  949. }
  950. }
  951. else
  952. {
  953. string kk = new_key + (new_key == "" ? "" : ".") + key;
  954. if (ob[key] == null)
  955. db.set_property_null(id, kk);
  956. if (ob[key].holds(typeof(bool)))
  957. db.set_property_bool(id, kk, (bool)ob[key]);
  958. if (ob[key].holds(typeof(double)))
  959. db.set_property_double(id, kk, (double)ob[key]);
  960. if (ob[key].holds(typeof(string)))
  961. db.set_property_string(id, kk, (string)ob[key]);
  962. if (ob[key].holds(typeof(Guid)))
  963. db.set_property_guid(id, kk, (Guid)ob[key]);
  964. if (ob[key].holds(typeof(Vector3)))
  965. db.set_property_vector3(id, kk, (Vector3)ob[key]);
  966. if (ob[key].holds(typeof(Quaternion)))
  967. db.set_property_quaternion(id, kk, (Quaternion)ob[key]);
  968. }
  969. }
  970. }
  971. // Un-does the last action and returns its ID, or -1 if there is no
  972. // action to undo.
  973. public int undo()
  974. {
  975. if (_undo_points.size() == 0)
  976. return -1;
  977. RestorePoint rp = _undo_points.read_restore_point();
  978. _redo_points.write_restore_point(rp.id, _redo.size(), rp.data);
  979. undo_until(rp.size);
  980. undo_redo(true, rp.id, rp.data);
  981. return rp.id;
  982. }
  983. // Re-does the last action and returns its ID, or -1 if there is no
  984. // action to redo.
  985. public int redo()
  986. {
  987. if (_redo_points.size() == 0)
  988. return -1;
  989. RestorePoint rp = _redo_points.read_restore_point();
  990. _undo_points.write_restore_point(rp.id, _undo.size(), rp.data);
  991. redo_until(rp.size);
  992. undo_redo(false, rp.id, rp.data);
  993. return rp.id;
  994. }
  995. private void undo_until(uint32 size)
  996. {
  997. undo_redo_until(size, _undo, _redo);
  998. }
  999. private void redo_until(uint32 size)
  1000. {
  1001. undo_redo_until(size, _redo, _undo);
  1002. }
  1003. private void undo_redo_until(uint32 size, Stack undo, Stack redo)
  1004. {
  1005. int dir = undo == _undo ? -1 : 1;
  1006. while (undo.size() != size)
  1007. {
  1008. uint32 type = undo.peek_type();
  1009. if (type == Action.CREATE)
  1010. {
  1011. Action t = undo.read_action();
  1012. assert(t == Action.CREATE);
  1013. Guid id = undo.read_guid();
  1014. redo.write_destroy_action(id);
  1015. create_internal(dir, id);
  1016. }
  1017. else if (type == Action.DESTROY)
  1018. {
  1019. Action t = undo.read_action();
  1020. assert(t == Action.DESTROY);
  1021. Guid id = undo.read_guid();
  1022. redo.write_create_action(id);
  1023. destroy_internal(dir, id);
  1024. }
  1025. else if (type == Action.SET_PROPERTY_NULL)
  1026. {
  1027. Action t = undo.read_action();
  1028. assert(t == Action.SET_PROPERTY_NULL);
  1029. Guid id = undo.read_guid();
  1030. string key = undo.read_string();
  1031. if (has_property(id, key))
  1032. {
  1033. if (get_data(id)[key].holds(typeof(bool)))
  1034. redo.write_set_property_bool_action(id, key, get_property_bool(id, key));
  1035. if (get_data(id)[key].holds(typeof(double)))
  1036. redo.write_set_property_double_action(id, key, get_property_double(id, key));
  1037. if (get_data(id)[key].holds(typeof(string)))
  1038. redo.write_set_property_string_action(id, key, get_property_string(id, key));
  1039. if (get_data(id)[key].holds(typeof(Guid)))
  1040. redo.write_set_property_guid_action(id, key, get_property_guid(id, key));
  1041. if (get_data(id)[key].holds(typeof(Vector3)))
  1042. redo.write_set_property_vector3_action(id, key, get_property_vector3(id, key));
  1043. if (get_data(id)[key].holds(typeof(Quaternion)))
  1044. redo.write_set_property_quaternion_action(id, key, get_property_quaternion(id, key));
  1045. }
  1046. else
  1047. {
  1048. redo.write_set_property_null_action(id, key);
  1049. }
  1050. set_property_internal(dir, id, key, null);
  1051. }
  1052. else if (type == Action.SET_PROPERTY_BOOL)
  1053. {
  1054. Action t = undo.read_action();
  1055. assert(t == Action.SET_PROPERTY_BOOL);
  1056. Guid id = undo.read_guid();
  1057. string key = undo.read_string();
  1058. bool val = undo.read_bool();
  1059. if (has_property(id, key))
  1060. redo.write_set_property_bool_action(id, key, get_property_bool(id, key));
  1061. else
  1062. redo.write_set_property_null_action(id, key);
  1063. set_property_internal(dir, id, key, val);
  1064. }
  1065. else if (type == Action.SET_PROPERTY_DOUBLE)
  1066. {
  1067. Action t = undo.read_action();
  1068. assert(t == Action.SET_PROPERTY_DOUBLE);
  1069. Guid id = undo.read_guid();
  1070. string key = undo.read_string();
  1071. double val = undo.read_double();
  1072. if (has_property(id, key))
  1073. redo.write_set_property_double_action(id, key, get_property_double(id, key));
  1074. else
  1075. redo.write_set_property_null_action(id, key);
  1076. set_property_internal(dir, id, key, val);
  1077. }
  1078. else if (type == Action.SET_PROPERTY_STRING)
  1079. {
  1080. Action t = undo.read_action();
  1081. assert(t == Action.SET_PROPERTY_STRING);
  1082. Guid id = undo.read_guid();
  1083. string key = undo.read_string();
  1084. string val = undo.read_string();
  1085. if (has_property(id, key))
  1086. redo.write_set_property_string_action(id, key, get_property_string(id, key));
  1087. else
  1088. redo.write_set_property_null_action(id, key);
  1089. set_property_internal(dir, id, key, val);
  1090. }
  1091. else if (type == Action.SET_PROPERTY_GUID)
  1092. {
  1093. Action t = undo.read_action();
  1094. assert(t == Action.SET_PROPERTY_GUID);
  1095. Guid id = undo.read_guid();
  1096. string key = undo.read_string();
  1097. Guid val = undo.read_guid();
  1098. if (has_property(id, key))
  1099. redo.write_set_property_guid_action(id, key, get_property_guid(id, key));
  1100. else
  1101. redo.write_set_property_null_action(id, key);
  1102. set_property_internal(dir, id, key, val);
  1103. }
  1104. else if (type == Action.SET_PROPERTY_VECTOR3)
  1105. {
  1106. Action t = undo.read_action();
  1107. assert(t == Action.SET_PROPERTY_VECTOR3);
  1108. Guid id = undo.read_guid();
  1109. string key = undo.read_string();
  1110. Vector3 val = undo.read_vector3();
  1111. if (has_property(id, key))
  1112. redo.write_set_property_vector3_action(id, key, get_property_vector3(id, key));
  1113. else
  1114. redo.write_set_property_null_action(id, key);
  1115. set_property_internal(dir, id, key, val);
  1116. }
  1117. else if (type == Action.SET_PROPERTY_QUATERNION)
  1118. {
  1119. Action t = undo.read_action();
  1120. assert(t == Action.SET_PROPERTY_QUATERNION);
  1121. Guid id = undo.read_guid();
  1122. string key = undo.read_string();
  1123. Quaternion val = undo.read_quaternion();
  1124. if (has_property(id, key))
  1125. redo.write_set_property_quaternion_action(id, key, get_property_quaternion(id, key));
  1126. else
  1127. redo.write_set_property_null_action(id, key);
  1128. set_property_internal(dir, id, key, val);
  1129. }
  1130. else if (type == Action.ADD_TO_SET)
  1131. {
  1132. Action t = undo.read_action();
  1133. assert(t == Action.ADD_TO_SET);
  1134. Guid id = undo.read_guid();
  1135. string key = undo.read_string();
  1136. Guid item_id = undo.read_guid();
  1137. redo.write_remove_from_set_action(id, key, item_id);
  1138. add_to_set_internal(dir, id, key, item_id);
  1139. }
  1140. else if (type == Action.REMOVE_FROM_SET)
  1141. {
  1142. Action t = undo.read_action();
  1143. assert(t == Action.REMOVE_FROM_SET);
  1144. Guid id = undo.read_guid();
  1145. string key = undo.read_string();
  1146. Guid item_id = undo.read_guid();
  1147. redo.write_add_to_set_action(id, key, item_id);
  1148. remove_from_set_internal(dir, id, key, item_id);
  1149. }
  1150. }
  1151. }
  1152. }
  1153. }