Просмотр исходного кода

tools: use single Database to load project objects

Daniele Bartolini 5 лет назад
Родитель
Сommit
f935ed8e6d

+ 41 - 15
tools/core/database.vala

@@ -338,30 +338,48 @@ public class Database
 	}
 
 	/// Saves database to path without marking it as not changed.
-	public void dump(string path)
+	public void dump(string path, Guid id)
 	{
-		Hashtable json = encode();
+		Hashtable json = encode(id);
 		SJSON.save(json, path);
 	}
 
 	/// Saves database to path.
-	public void save(string path)
+	public void save(string path, Guid id)
 	{
-		dump(path);
+		dump(path, id);
 		_distance_from_last_sync = 0;
 	}
 
-	/// Loads database from path.
-	public void load(string path)
+	// Loads the database with the object stored at @a path, without resetting the
+	// database. This makes it possible to load multiple objects from distinct
+	// paths in the same database. @a resource_path is used as a key in the
+	// database to refer to the object that has been loaded. This is useful when
+	// you do not have the object ID but only its path, as it is often the case
+	// since resources use paths and not IDs to reference each other.
+	public Guid load_more(string path, string resource_path)
 	{
 		Hashtable json = SJSON.load(path);
-		decode(json);
+		Guid id = decode(json);
+
+		// Create a mapping between the path and the object it has been loaded into.
+		set_property_internal(1, GUID_ZERO, resource_path, id);
+
 		_distance_from_last_sync = 0;
+		return id;
+	}
+
+	/// Loads the database with the object stored at @a path.
+	public Guid load(string path, string resource_path)
+	{
+		reset();
+		return load_more(path, resource_path);
 	}
 
-	private Hashtable encode()
+	/// Encodes the object @a id into SJSON object.
+	private Hashtable encode(Guid id)
 	{
-		return encode_object(GUID_ZERO, _data);
+		return encode_object(id, get_data(id));
 	}
 
 	private static bool is_valid_value(Value? value)
@@ -409,10 +427,18 @@ public class Database
 	}
 #endif // CROWN_DEBUG
 
-	public void decode(Hashtable json)
+	// Decodes the @a json data inside the database object @a id.
+	public Guid decode(Hashtable json)
 	{
-		reset();
-		decode_object(GUID_ZERO, "", json);
+		Guid id;
+		if (json.has_key("id"))
+			id = Guid.parse((string)json["id"]);
+		else
+			id = Guid.new_guid();
+
+		create_internal(1, id);
+		decode_object(id, "", json);
+		return id;
 	}
 
 	private void decode_object(Guid id, string db_key, Hashtable json)
@@ -574,8 +600,7 @@ public class Database
 			ArrayList<Value?> arr = new Gee.ArrayList<Value?>();
 			foreach (Guid id in hs)
 			{
-				HashMap<string, Value?> objs = (HashMap<string, Value?>)_data["_objects"];
-				arr.add(encode_object(id, (HashMap<string, Value?>)objs[id.to_string()]));
+				arr.add(encode_object(id, get_data(id)));
 			}
 			return arr;
 		}
@@ -589,7 +614,8 @@ public class Database
 	{
 		assert(has_object(id));
 
-		return (HashMap<string, Value?>)(id == GUID_ZERO ? _data : ((HashMap<string, Value?>)_data["_objects"])[id.to_string()]);
+		HashMap<string, Value?> objects = (HashMap<string, Value?>)_data["_objects"];
+		return (HashMap<string, Value?>)(id == GUID_ZERO ? _data : objects[id.to_string()]);
 	}
 
 	private void create_internal(int dir, Guid id)

+ 48 - 43
tools/level_editor/level.vala

@@ -17,7 +17,6 @@ public class Level
 
 	// Data
 	public Database _db;
-	public Database _prefabs;
 	public Gee.HashSet<string> _loaded_prefabs;
 	public Gee.ArrayList<Guid?> _selection;
 
@@ -26,6 +25,7 @@ public class Level
 
 	public string _name;
 	public string _path;
+	public Guid _id;
 
 	// Signals
 	public signal void selection_changed(Gee.ArrayList<Guid?> selection);
@@ -42,7 +42,6 @@ public class Level
 		_db = db;
 		_db.undo_redo.connect(undo_redo_action);
 
-		_prefabs = new Database();
 		_loaded_prefabs = new Gee.HashSet<string>();
 		_selection = new Gee.ArrayList<Guid?>();
 
@@ -53,7 +52,6 @@ public class Level
 	public void reset()
 	{
 		_db.reset();
-		_prefabs.reset();
 		_loaded_prefabs.clear();
 
 		_selection.clear();
@@ -64,17 +62,22 @@ public class Level
 
 		_name = null;
 		_path = null;
+		_id = GUID_ZERO;
 	}
 
 	public void load(string name)
 	{
 		reset();
 
-		string path = Path.build_filename(_project.source_dir(), name + ".level");
+		string resource_path = name + ".level";
+		string path = Path.build_filename(_project.source_dir(), resource_path);
 
-		_db.load(path);
+		_id = _db.load(path, resource_path);
 		_name = name;
 		_path = path;
+
+		// FIXME: hack to keep the LevelTreeView working.
+		_db.key_changed(_id, "units");
 	}
 
 	public void load_empty_level()
@@ -82,18 +85,22 @@ public class Level
 		reset();
 
 		string name = LEVEL_EMPTY;
-		string path = Path.build_filename(_project.toolchain_dir(), name + ".level");
+		string resource_path = name + ".level";
+		string path = Path.build_filename(_project.toolchain_dir(), resource_path);
 
-		_db.load(path);
+		_id = _db.load(path, resource_path);
 		_name = name;
 		_path = null;
+
+		// FIXME: hack to keep the LevelTreeView working.
+		_db.key_changed(_id, "units");
 	}
 
 	public void save(string name)
 	{
 		string path = Path.build_filename(_project.source_dir(), name + ".level");
 
-		_db.save(path);
+		_db.save(path, _id);
 		_path = path;
 		_name = name;
 	}
@@ -122,7 +129,7 @@ public class Level
 			_db.add_restore_point((int)ActionType.DESTROY_UNIT, units);
 			foreach (Guid id in units)
 			{
-				_db.remove_from_set(GUID_ZERO, "units", id);
+				_db.remove_from_set(_id, "units", id);
 				_db.destroy(id);
 			}
 		}
@@ -132,7 +139,7 @@ public class Level
 			_db.add_restore_point((int)ActionType.DESTROY_SOUND, sounds);
 			foreach (Guid id in sounds)
 			{
-				_db.remove_from_set(GUID_ZERO, "sounds", id);
+				_db.remove_from_set(_id, "sounds", id);
 				_db.destroy(id);
 			}
 		}
@@ -193,11 +200,11 @@ public class Level
 
 			if (is_unit(ids[i]))
 			{
-				_db.add_to_set(GUID_ZERO, "units", new_ids[i]);
+				_db.add_to_set(_id, "units", new_ids[i]);
 			}
 			else if (is_sound(ids[i]))
 			{
-				_db.add_to_set(GUID_ZERO, "sounds", new_ids[i]);
+				_db.add_to_set(_id, "sounds", new_ids[i]);
 			}
 		}
 		send_spawn_objects(new_ids);
@@ -213,7 +220,7 @@ public class Level
 		_db.set_property_string(id, "editor.name", "unit_%04u".printf(_num_units++));
 		_db.set_property_string(id, "prefab", name);
 
-		Unit unit = new Unit(_db, id, _prefabs);
+		Unit unit = new Unit(_db, id);
 		Guid component_id;
 		if (unit.has_component(out component_id, "transform"))
 		{
@@ -228,7 +235,7 @@ public class Level
 			_db.set_property_quaternion(id, "rotation", rot);
 			_db.set_property_vector3   (id, "scale", scl);
 		}
-		_db.add_to_set(GUID_ZERO, "units", id);
+		_db.add_to_set(_id, "units", id);
 	}
 
 	public void on_sound_spawned(Guid id, string name, Vector3 pos, Quaternion rot, Vector3 scl, double range, double volume, bool loop)
@@ -242,7 +249,7 @@ public class Level
 		_db.set_property_double    (id, "range", range);
 		_db.set_property_double    (id, "volume", volume);
 		_db.set_property_bool      (id, "loop", loop);
-		_db.add_to_set(GUID_ZERO, "sounds", id);
+		_db.add_to_set(_id, "sounds", id);
 	}
 
 	public void on_move_objects(Guid[] ids, Vector3[] positions, Quaternion[] rotations, Vector3[] scales)
@@ -258,7 +265,7 @@ public class Level
 
 			if (is_unit(id))
 			{
-				Unit unit = new Unit(_db, id, _prefabs);
+				Unit unit = new Unit(_db, id);
 				Guid component_id;
 				if (unit.has_component(out component_id, "transform"))
 				{
@@ -306,7 +313,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_LIGHT, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string (component_id, "data.type",       type);
 		unit.set_component_property_double (component_id, "data.range",      range);
 		unit.set_component_property_double (component_id, "data.intensity",  intensity);
@@ -321,7 +328,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_MESH, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.mesh_resource", mesh_resource);
 		unit.set_component_property_string(component_id, "data.geometry_name", geometry);
 		unit.set_component_property_string(component_id, "data.material", material);
@@ -335,7 +342,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_SPRITE, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_double(component_id, "data.layer", layer);
 		unit.set_component_property_double(component_id, "data.depth", depth);
 		unit.set_component_property_string(component_id, "data.material", material);
@@ -350,7 +357,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_CAMERA, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.projection", projection);
 		unit.set_component_property_double(component_id, "data.fov", fov);
 		unit.set_component_property_double(component_id, "data.near_range", near_range);
@@ -364,7 +371,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_COLLIDER, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.shape", shape);
 		unit.set_component_property_string(component_id, "data.scene", scene);
 		unit.set_component_property_string(component_id, "data.name", name);
@@ -377,7 +384,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_ACTOR, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.class", class);
 		unit.set_component_property_string(component_id, "data.collision_filter", collision_filter);
 		unit.set_component_property_string(component_id, "data.material", material);
@@ -397,7 +404,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_SCRIPT, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.script_resource", script_resource);
 		unit.set_component_property_string(component_id, "type", "script");
 	}
@@ -406,7 +413,7 @@ public class Level
 	{
 		_db.add_restore_point((int)ActionType.SET_ANIMATION_STATE_MACHINE, new Guid[] { unit_id });
 
-		Unit unit = new Unit(_db, unit_id, _prefabs);
+		Unit unit = new Unit(_db, unit_id);
 		unit.set_component_property_string(component_id, "data.state_machine_resource", state_machine_resource);
 		unit.set_component_property_string(component_id, "type", "animation_state_machine");
 	}
@@ -490,8 +497,8 @@ public class Level
 
 	public void send_level()
 	{
-		HashSet<Guid?> units  = _db.get_property_set(GUID_ZERO, "units", new HashSet<Guid?>());
-		HashSet<Guid?> sounds = _db.get_property_set(GUID_ZERO, "sounds", new HashSet<Guid?>());
+		HashSet<Guid?> units  = _db.get_property_set(_id, "units", new HashSet<Guid?>());
+		HashSet<Guid?> sounds = _db.get_property_set(_id, "sounds", new HashSet<Guid?>());
 
 		Guid[] unit_ids = new Guid[units.size];
 		Guid[] sound_ids = new Guid[sounds.size];
@@ -524,21 +531,19 @@ public class Level
 		if (_loaded_prefabs.contains(name))
 			return;
 
-		Database prefab_db = new Database();
+		// Try to load from toolchain directory first.
+		string resource_path = name + ".unit";
+		string path = Path.build_filename(_project.toolchain_dir(), resource_path);
+		if (!File.new_for_path(path).query_exists())
+			path = Path.build_filename(_project.source_dir(), resource_path);
 
-		// Try to load from toolchain directory first
-		File file = File.new_for_path(Path.build_filename(_project.toolchain_dir(), name + ".unit"));
-		if (file.query_exists())
-			prefab_db.load(file.get_path());
-		else
-			prefab_db.load(Path.build_filename(_project.source_dir(), name + ".unit"));
+		Guid prefab_id = _db.load_more(path, resource_path);
 
 		// Recursively load all sub-prefabs
-		Value? prefab = prefab_db.get_property(GUID_ZERO, "prefab");
+		Value? prefab = _db.get_property(prefab_id, "prefab");
 		if (prefab != null)
 			load_prefab((string)prefab);
 
-		prefab_db.copy_to(_prefabs, name);
 		_loaded_prefabs.add(name);
 	}
 
@@ -546,7 +551,7 @@ public class Level
 	{
 		foreach (Guid unit_id in unit_ids)
 		{
-			Unit unit = new Unit(_db, unit_id, _prefabs);
+			Unit unit = new Unit(_db, unit_id);
 
 			if (unit.has_prefab())
 				load_prefab(_db.get_property_string(unit_id, "prefab"));
@@ -683,7 +688,7 @@ public class Level
 					{
 						Guid unit_id = ids[i];
 
-						Unit unit = new Unit(_db, unit_id, _prefabs);
+						Unit unit = new Unit(_db, unit_id);
 						Guid component_id;
 						if (unit.has_component(out component_id, "transform"))
 						{
@@ -735,7 +740,7 @@ public class Level
 			{
 				Guid unit_id = data[0];
 
-				Unit unit = new Unit(_db, unit_id, _prefabs);
+				Unit unit = new Unit(_db, unit_id);
 				Guid component_id;
 				unit.has_component(out component_id, "light");
 
@@ -755,7 +760,7 @@ public class Level
 			{
 				Guid unit_id = data[0];
 
-				Unit unit = new Unit(_db, unit_id, _prefabs);
+				Unit unit = new Unit(_db, unit_id);
 				Guid component_id;
 				unit.has_component(out component_id, "mesh_renderer");
 
@@ -773,7 +778,7 @@ public class Level
 			{
 				Guid unit_id = data[0];
 
-				Unit unit = new Unit(_db, unit_id, _prefabs);
+				Unit unit = new Unit(_db, unit_id);
 				Guid component_id;
 				unit.has_component(out component_id, "sprite_renderer");
 
@@ -792,7 +797,7 @@ public class Level
 			{
 				Guid unit_id = data[0];
 
-				Unit unit = new Unit(_db, unit_id, _prefabs);
+				Unit unit = new Unit(_db, unit_id);
 				Guid component_id;
 				unit.has_component(out component_id, "camera");
 
@@ -835,12 +840,12 @@ public class Level
 
 	public bool is_unit(Guid id)
 	{
-		return _db.get_property_set(GUID_ZERO, "units", new HashSet<Guid?>()).contains(id);
+		return _db.get_property_set(_id, "units", new HashSet<Guid?>()).contains(id);
 	}
 
 	public bool is_sound(Guid id)
 	{
-		return _db.get_property_set(GUID_ZERO, "sounds", new HashSet<Guid?>()).contains(id);
+		return _db.get_property_set(_id, "sounds", new HashSet<Guid?>()).contains(id);
 	}
 }
 

+ 12 - 1
tools/level_editor/level_editor.vala

@@ -1109,7 +1109,15 @@ public class LevelEditorApplication : Gtk.Application
 
 	private async void start_game(StartGame sg)
 	{
-		_project.dump_test_level(_database);
+		// Save test level to file
+		_database.dump(_project._level_editor_test_level.get_path(), _level._id);
+
+		// Save temporary package to reference test level
+		ArrayList<Value?> level = new ArrayList<Value?>();
+		level.add("_level_editor_test");
+		Hashtable package = new Hashtable();
+		package["level"] = level;
+		SJSON.save(package, _project._level_editor_test_package.get_path());
 
 		bool success = yield _data_compiler.compile(_project.data_dir(), _project.platform());
 		if (!success)
@@ -1309,6 +1317,9 @@ public class LevelEditorApplication : Gtk.Application
 	{
 		_level.load_empty_level();
 		_level.send_level();
+
+		// FIXME: hack to keep update_active_windo_title() working.
+		_database.key_changed(_level._id, "");
 	}
 
 	private void update_active_window_title()

+ 4 - 4
tools/level_editor/level_tree_view.vala

@@ -369,7 +369,7 @@ public class LevelTreeView : Gtk.Box
 
 	private void on_database_key_changed(Guid id, string key)
 	{
-		if (id != GUID_ZERO)
+		if (id != _level._id)
 			return;
 
 		if (key != "units" && key != "sounds")
@@ -428,12 +428,12 @@ public class LevelTreeView : Gtk.Box
 			, -1
 			);
 
-		HashSet<Guid?> units  = _db.get_property_set(GUID_ZERO, "units", new HashSet<Guid?>());
-		HashSet<Guid?> sounds = _db.get_property_set(GUID_ZERO, "sounds", new HashSet<Guid?>());
+		HashSet<Guid?> units  = _db.get_property_set(_level._id, "units", new HashSet<Guid?>());
+		HashSet<Guid?> sounds = _db.get_property_set(_level._id, "sounds", new HashSet<Guid?>());
 
 		foreach (Guid unit in units)
 		{
-			Unit u = new Unit(_level._db, unit, _level._prefabs);
+			Unit u = new Unit(_level._db, unit);
 
 			int item_type = LevelTreeView.ItemType.UNIT;
 			Gtk.TreeIter tree_iter = units_iter;

+ 0 - 13
tools/level_editor/project.vala

@@ -342,19 +342,6 @@ public class Project
 		return file.has_prefix(_source_dir);
 	}
 
-	public void dump_test_level(Database db)
-	{
-		// Save test level to file
-		db.dump(_level_editor_test_level.get_path());
-
-		// Save temporary package to reference test level
-		ArrayList<Value?> level = new ArrayList<Value?>();
-		level.add("_level_editor_test");
-		Hashtable package = new Hashtable();
-		package["level"] = level;
-		SJSON.save(package, _level_editor_test_package.get_path());
-	}
-
 	public void delete_garbage()
 	{
 		try

+ 10 - 13
tools/level_editor/properties_view.vala

@@ -81,8 +81,6 @@ public class TransformPropertyGrid : PropertyGrid
 	{
 		// Data
 		_level = level;
-		_id = GUID_ZERO;
-		_component_id = GUID_ZERO;
 
 		// Widgets
 		_position = new EntryPosition();
@@ -107,7 +105,7 @@ public class TransformPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_position.value = unit.get_component_property_vector3   (_component_id, "data.position");
 		_rotation.value = unit.get_component_property_quaternion(_component_id, "data.rotation");
 		_scale.value    = unit.get_component_property_vector3   (_component_id, "data.scale");
@@ -159,7 +157,7 @@ public class MeshRendererPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_mesh_resource.value = unit.get_component_property_string(_component_id, "data.mesh_resource");
 		_geometry.text       = unit.get_component_property_string(_component_id, "data.geometry_name");
 		_material.value      = unit.get_component_property_string(_component_id, "data.material");
@@ -217,7 +215,7 @@ public class SpriteRendererPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_sprite_resource.value = unit.get_component_property_string(_component_id, "data.sprite_resource");
 		_material.value        = unit.get_component_property_string(_component_id, "data.material");
 		_layer.value           = unit.get_component_property_double(_component_id, "data.layer");
@@ -279,7 +277,7 @@ public class LightPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		string type       = unit.get_component_property_string (_component_id, "data.type");
 		double range      = unit.get_component_property_double (_component_id, "data.range");
 		double intensity  = unit.get_component_property_double (_component_id, "data.intensity");
@@ -341,7 +339,7 @@ public class CameraPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 
 		_projection.value = unit.get_component_property_string(_component_id, "data.projection");
 		_fov.value        = unit.get_component_property_double(_component_id, "data.fov") * (180.0/Math.PI);
@@ -399,7 +397,7 @@ public class ColliderPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 
 		Value? source = unit.get_component_property(_component_id, "data.source");
 		if (source != null)
@@ -478,7 +476,7 @@ public class ActorPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_class.value           = unit.get_component_property_string(_component_id, "data.class");
 		_collision_filter.text = unit.get_component_property_string(_component_id, "data.collision_filter");
 		_material.text         = unit.get_component_property_string(_component_id, "data.material");
@@ -516,7 +514,7 @@ public class ScriptPropertyGrid : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_script_resource.value = unit.get_component_property_string(_component_id, "data.script_resource");
 	}
 }
@@ -551,7 +549,7 @@ public class AnimationStateMachine : PropertyGrid
 
 	public override void update()
 	{
-		Unit unit = new Unit(_level._db, _id, _level._prefabs);
+		Unit unit = new Unit(_level._db, _id);
 		_state_machine_resource.value = unit.get_component_property_string(_component_id, "data.state_machine_resource");
 	}
 }
@@ -598,7 +596,6 @@ public class SoundTransformView : PropertyGrid
 	{
 		// Data
 		_level = level;
-		_id = GUID_ZERO;
 
 		// Widgets
 		_position = new EntryPosition();
@@ -773,7 +770,7 @@ public class PropertiesView : Gtk.Bin
 			{
 				Gtk.Expander expander = _expanders[entry.type];
 
-				Unit unit = new Unit(_level._db, id, _level._prefabs);
+				Unit unit = new Unit(_level._db, id);
 				Guid component_id;
 				if (unit.has_component(out component_id, entry.type) || entry.type == "name")
 				{

+ 39 - 116
tools/level_editor/unit.vala

@@ -10,39 +10,12 @@ namespace Crown
 public class Unit
 {
 	public Database _db;
-	public Guid _unit;
-	public Database _prefabs;
+	public Guid _id;
 
-	public Unit(Database db, Guid unit, Database? prefabs)
+	public Unit(Database db, Guid id)
 	{
 		_db = db;
-		_unit = unit;
-		_prefabs = prefabs != null ? prefabs : new Database();
-	}
-
-	public Value? prefab_get_component_property(Guid component_id, string key, string prefab)
-	{
-		Value? val;
-
-		// Search in components
-		val = _prefabs.get_property(GUID_ZERO, prefab + ".components");
-		if (val != null)
-		{
-			if (((HashSet<Guid?>)val).contains(component_id))
-				return _prefabs.get_property(component_id, key);
-		}
-
-		// Search in modified_components
-		val = _prefabs.get_property(GUID_ZERO, prefab + ".modified_components.#" + component_id.to_string() + "." + key);
-		if (val != null)
-			return val;
-
-		// Search in prefab
-		val = _prefabs.get_property(GUID_ZERO, prefab + ".prefab");
-		if (val != null)
-			return prefab_get_component_property(component_id, key, (string)val);
-
-		return null;
+		_id = id;
 	}
 
 	public Value? get_component_property(Guid component_id, string key)
@@ -50,7 +23,7 @@ public class Unit
 		Value? val;
 
 		// Search in components
-		val = _db.get_property(_unit, "components");
+		val = _db.get_property(_id, "components");
 		if (val != null)
 		{
 			if (((HashSet<Guid?>)val).contains(component_id))
@@ -58,14 +31,21 @@ public class Unit
 		}
 
 		// Search in modified_components
-		val = _db.get_property(_unit, "modified_components.#" + component_id.to_string() + "." + key);
+		val = _db.get_property(_id, "modified_components.#" + component_id.to_string() + "." + key);
 		if (val != null)
 			return val;
 
 		// Search in prefab
-		val = _db.get_property(_unit, "prefab");
+		val = _db.get_property(_id, "prefab");
 		if (val != null)
-			return prefab_get_component_property(component_id, key, (string)val);
+		{
+			// Convert prefab path to object ID.
+			string prefab = (string)val;
+			Guid prefab_id = _db.get_property_guid(GUID_ZERO, prefab + ".unit");
+
+			Unit unit = new Unit(_db, prefab_id);
+			return unit.get_component_property(component_id, key);
+		}
 
 		return null;
 	}
@@ -103,143 +83,82 @@ public class Unit
 	public void set_component_property_bool(Guid component_id, string key, bool val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_bool(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_bool(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
+		_db.set_property_bool(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
 	public void set_component_property_double(Guid component_id, string key, double val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_double(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_double(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
+		_db.set_property_double(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
 	public void set_component_property_string(Guid component_id, string key, string val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_string(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_string(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
+		_db.set_property_string(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
 	public void set_component_property_guid(Guid component_id, string key, Guid val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_guid(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_guid(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
+		_db.set_property_guid(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
 	public void set_component_property_vector3(Guid component_id, string key, Vector3 val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_vector3(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_vector3(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
+		_db.set_property_vector3(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
 	public void set_component_property_quaternion(Guid component_id, string key, Quaternion val)
 	{
 		// Search in components
-		Value? components = _db.get_property(_unit, "components");
+		Value? components = _db.get_property(_id, "components");
 		if (components != null && ((HashSet<Guid?>)components).contains(component_id))
 		{
 			_db.set_property_quaternion(component_id, key, val);
 			return;
 		}
 
-		_db.set_property_quaternion(_unit, "modified_components.#" + component_id.to_string() + "." + key, val);
-	}
-
-	public static bool prefab_has_component_static(out Guid component_id, string component_type, Database prefabs_db, string prefab)
-	{
-		Value? val;
-
-		// Search in components
-		val = prefabs_db.get_property(GUID_ZERO, prefab + ".components");
-		if (val != null)
-		{
-			foreach (Guid id in (HashSet<Guid?>)val)
-			{
-				if((string)prefabs_db.get_property(id, "type") == component_type)
-				{
-					component_id = id;
-					return true;
-				}
-			}
-		}
-
-		// Search in modified_components
-		string[] keys = prefabs_db.get_keys(GUID_ZERO);
-		foreach (string key in keys)
-		{
-			if (!key.has_prefix(prefab + ".modified_components.#"))
-				continue;
-
-			// 0                   21                                   58  62
-			// |                    |                                    |   |
-			// modified_components.#f56420ad-7f9c-4cca-aca5-350f366e0dc0.type
-			int aa = 21 + prefab.length+1;
-			int bb = 57 + prefab.length+1;
-			int cc = 58 + prefab.length+1;
-			int dd = 62 + prefab.length+1;
-			string id = key[aa:bb];
-			string suffix = key[cc:dd];
-
-			if (!suffix.has_prefix("type"))
-				continue;
-
-			Value? type = prefabs_db.get_property(GUID_ZERO, key);
-			if (type != null && (string)type == component_type)
-			{
-				component_id = Guid.parse(id);
-				return true;
-			}
-		}
-
-		// Search in prefab
-		val = prefabs_db.get_property(GUID_ZERO, prefab + ".prefab");
-		if (val != null)
-		{
-			return prefab_has_component_static(out component_id
-				, component_type
-				, prefabs_db
-				, (string)val
-				);
-		}
-
-		component_id = GUID_ZERO;
-		return false;
+		_db.set_property_quaternion(_id, "modified_components.#" + component_id.to_string() + "." + key, val);
 	}
 
-	public static bool has_component_static(out Guid component_id, string component_type, Database db, Database prefabs_db, Guid unit_id)
+	public static bool has_component_static(out Guid component_id, string component_type, Database db, Guid unit_id)
 	{
 		Value? val;
 
@@ -289,10 +208,14 @@ public class Unit
 		val = db.get_property(unit_id, "prefab");
 		if (val != null)
 		{
-			return prefab_has_component_static(out component_id
+			// Convert prefab path to object ID.
+			string prefab = (string)val;
+			Guid prefab_id = db.get_property_guid(GUID_ZERO, prefab + ".unit");
+
+			return has_component_static(out component_id
 				, component_type
-				, prefabs_db
-				, (string)val
+				, db
+				, prefab_id
 				);
 		}
 
@@ -303,32 +226,32 @@ public class Unit
 	/// Returns whether the unit has the component_type.
 	public bool has_component(out Guid component_id, string component_type)
 	{
-		return Unit.has_component_static(out component_id, component_type, _db, _prefabs, _unit);
+		return Unit.has_component_static(out component_id, component_type, _db, _id);
 	}
 
 	public void remove_component(Guid component_id)
 	{
-		_db.remove_from_set(GUID_ZERO, "components", component_id);
+		_db.remove_from_set(_id, "components", component_id);
 	}
 
 	/// Returns whether the unit has a prefab.
 	public bool has_prefab()
 	{
-		return _db.has_property(_unit, "prefab");
+		return _db.has_property(_id, "prefab");
 	}
 
 	/// Returns whether the unit is a light unit.
 	public bool is_light()
 	{
 		return has_prefab()
-			&& _db.get_property_string(_unit, "prefab") == "core/units/light";
+			&& _db.get_property_string(_id, "prefab") == "core/units/light";
 	}
 
 	/// Returns whether the unit is a camera unit.
 	public bool is_camera()
 	{
 		return has_prefab()
-			&& _db.get_property_string(_unit, "prefab") == "core/units/camera";
+			&& _db.get_property_string(_id, "prefab") == "core/units/camera";
 	}
 }
 

+ 12 - 9
tools/resource/mesh_resource.vala

@@ -12,7 +12,7 @@ public class MeshResource
 {
 	public static void create_components(Database db, Guid parent_unit_id, Guid unit_id, string material_name, string resource_name, string node_name, Hashtable node)
 	{
-		Unit unit = new Unit(db, unit_id, null);
+		Unit unit = new Unit(db, unit_id);
 
 		Matrix4x4 matrix_local = Matrix4x4.from_array((ArrayList<Value?>)node["matrix_local"]);
 		Vector3 position = matrix_local.t.to_vector3();
@@ -185,11 +185,14 @@ public class MeshResource
 
 			// Generate .unit
 			Database db = new Database();
+			Guid unit_id = Guid.new_guid();
 
 			// Do not overwrite existing .unit
 			string unit_name = Path.build_filename(project.source_dir(), resource_name) + ".unit";
 			if (File.new_for_path(unit_name).query_exists())
-				db.load(unit_name);
+				unit_id = db.load(unit_name, resource_path + ".unit");
+			else
+				db.create(unit_id);
 
 			Hashtable mesh = SJSON.load(filename_i);
 			Hashtable mesh_nodes = (Hashtable)mesh["nodes"];
@@ -199,7 +202,7 @@ public class MeshResource
 				// Create an extra "root" unit to accommodate multiple root objects. This
 				// "root" unit will only have a transform centered at origin to allow other
 				// objects to be linked to it via the SceneGraph.
-				Unit unit = new Unit(db, GUID_ZERO, null);
+				Unit unit = new Unit(db, unit_id);
 
 				Guid component_id;
 				if (unit.has_component(out component_id, "transform"))
@@ -218,24 +221,24 @@ public class MeshResource
 					db.set_property_vector3   (component_id, "data.scale", VECTOR3_ONE);
 					db.set_property_string    (component_id, "type", "transform");
 
-					db.add_to_set(GUID_ZERO, "components", component_id);
+					db.add_to_set(unit_id, "components", component_id);
 				}
 			}
 
-			Guid new_unit_id = GUID_ZERO;
+			Guid new_unit_id = unit_id;
 			foreach (var entry in mesh_nodes.entries)
 			{
 				if (mesh_nodes.size > 1)
 				{
-					// If the mesh contains multiple root objects, create a new GUID for each
-					// one of those, otherwise use the special GUID_ZERO.
+					// If the mesh contains multiple root objects, create a new unit for each
+					// one of those, otherwise put the components inside the base unit.
 					new_unit_id = Guid.new_guid();
 					db.create(new_unit_id);
 				}
-				create_components(db, GUID_ZERO, new_unit_id, material_name, resource_name, entry.key, (Hashtable)entry.value);
+				create_components(db, unit_id, new_unit_id, material_name, resource_name, entry.key, (Hashtable)entry.value);
 			}
 
-			db.save(unit_name);
+			db.save(unit_name, unit_id);
 		}
 
 		return 0;

+ 12 - 9
tools/resource/sprite_resource.vala

@@ -156,13 +156,16 @@ public class SpriteResource
 
 			// Generate .unit
 			Database db = new Database();
+			Guid unit_id = Guid.new_guid();
 
 			// Do not overwrite existing .unit
 			string unit_name = Path.build_filename(project.source_dir(), resource_path) + ".unit";
 			if (File.new_for_path(unit_name).query_exists())
-				db.load(unit_name);
+				unit_id = db.load(unit_name, resource_path + ".unit");
+			else
+				db.create(unit_id);
 
-			Unit unit = new Unit(db, GUID_ZERO, null);
+			Unit unit = new Unit(db, unit_id);
 
 			// Create transform
 			{
@@ -183,7 +186,7 @@ public class SpriteResource
 					db.set_property_vector3   (component_id, "data.scale", VECTOR3_ONE);
 					db.set_property_string    (component_id, "type", "transform");
 
-					db.add_to_set(GUID_ZERO, "components", component_id);
+					db.add_to_set(unit_id, "components", component_id);
 				}
 			}
 
@@ -210,7 +213,7 @@ public class SpriteResource
 					db.set_property_bool  (component_id, "data.visible", true);
 					db.set_property_string(component_id, "type", "sprite_renderer");
 
-					db.add_to_set(GUID_ZERO, "components", component_id);
+					db.add_to_set(unit_id, "components", component_id);
 				}
 			}
 
@@ -304,7 +307,7 @@ public class SpriteResource
 						}
 						db.set_property_string(component_id, "type", "collider");
 
-						db.add_to_set(GUID_ZERO, "components", component_id);
+						db.add_to_set(unit_id, "components", component_id);
 					}
 				}
 
@@ -341,7 +344,7 @@ public class SpriteResource
 						db.set_property_string(component_id, "data.material", "default");
 						db.set_property_string(component_id, "type", "actor");
 
-						db.add_to_set(GUID_ZERO, "components", component_id);
+						db.add_to_set(unit_id, "components", component_id);
 					}
 				}
 			}
@@ -351,17 +354,17 @@ public class SpriteResource
 				Guid component_id;
 				if (unit.has_component(out component_id, "collider"))
 				{
-					db.remove_from_set(GUID_ZERO, "components", component_id);
+					db.remove_from_set(unit_id, "components", component_id);
 					db.destroy(component_id);
 				}
 				if (unit.has_component(out component_id, "actor"))
 				{
-					db.remove_from_set(GUID_ZERO, "components", component_id);
+					db.remove_from_set(unit_id, "components", component_id);
 					db.destroy(component_id);
 				}
 			}
 
-			db.save(unit_name);
+			db.save(unit_name, unit_id);
 		}
 
 		return 0;