Browse Source

tools: accumulate then send in bulk

Also send frame() once, at the end.
Daniele Bartolini 1 year ago
parent
commit
f4dba847db

+ 1 - 0
docs/changelog.rst

@@ -8,6 +8,7 @@ Changelog
 
 * Fixed a crash when editing many objects simultaneusly.
 * Fixed a crash when trying to load levels with many objects.
+* Fixed an issue that prevented undo/redo operations to be executed in bulk.
 
 **Runtime**
 

+ 12 - 0
tools/level_editor/level.vala

@@ -276,6 +276,18 @@ public class Level
 		}
 	}
 
+	public void generate_change_objects(StringBuilder sb, Guid?[] object_ids)
+	{
+		int i = 0;
+		while (i < object_ids.length) {
+			if (_db.object_type(object_ids[i]) == OBJECT_TYPE_UNIT) {
+				i += Unit.generate_change_commands(sb, object_ids[i:object_ids.length], _db);
+			} else if (_db.object_type(object_ids[i]) == OBJECT_TYPE_SOUND_SOURCE) {
+				i += Sound.generate_change_sound_commands(sb, object_ids[i:object_ids.length], _db);
+			}
+		}
+	}
+
 	public void send_level()
 	{
 		Gee.ArrayList<Guid?> unit_ids = new Gee.ArrayList<Guid?>();

+ 8 - 24
tools/level_editor/level_editor.vala

@@ -1435,23 +1435,11 @@ public class LevelEditorApplication : Gtk.Application
 		_level.selection_changed(_level._selection);
 	}
 
-	private void on_object_changed(Guid object_id, Guid? component_id)
+	private void on_objects_changed(Guid?[] object_ids)
 	{
-		string object_type = _database.object_type(object_id);
-
-		if (object_type == OBJECT_TYPE_UNIT) {
-			Unit unit = new Unit(_database, object_id);
-			if (component_id == null)
-				unit.send(_editor);
-			else
-				unit.send_component(_editor, object_id, component_id);
-		} else if (object_type == OBJECT_TYPE_SOUND_SOURCE) {
-			Sound sound = new Sound(_database, object_id);
-			sound.send(_editor);
-		} else {
-			logw("Object changed with no handler: %s".printf(object_type));
-		}
-
+		StringBuilder sb = new StringBuilder();
+		_level.generate_change_objects(sb, object_ids);
+		_editor.send_script(sb.str);
 		_editor.send(DeviceApi.frame());
 	}
 
@@ -1484,11 +1472,11 @@ public class LevelEditorApplication : Gtk.Application
 		case ActionType.SET_ANIMATION_STATE_MACHINE:
 		case ActionType.SET_SOUND:
 			if ((flags & ActionTypeFlags.FROM_SERVER) == 0)
-				on_object_changed(data[0], data[1]);
+				on_objects_changed(data);
 			break;
 
 		case ActionType.OBJECT_SET_EDITOR_NAME:
-			on_object_changed(data[0], null);
+			on_objects_changed(data);
 			_level.object_editor_name_changed(data[0], _level.object_editor_name(data[0]));
 			break;
 
@@ -1522,10 +1510,6 @@ public class LevelEditorApplication : Gtk.Application
 			break;
 
 		case ActionType.MOVE_OBJECTS:
-			for (int i = 0; i < data.length; ++i)
-				on_object_changed(data[i], null);
-			break;
-
 		case ActionType.SET_TRANSFORM:
 		case ActionType.SET_LIGHT:
 		case ActionType.SET_MESH:
@@ -1536,11 +1520,11 @@ public class LevelEditorApplication : Gtk.Application
 		case ActionType.SET_SCRIPT:
 		case ActionType.SET_ANIMATION_STATE_MACHINE:
 		case ActionType.SET_SOUND:
-			on_object_changed(data[0], data[1]);
+			on_objects_changed(data);
 			break;
 
 		case ActionType.OBJECT_SET_EDITOR_NAME:
-			on_object_changed(data[0], null);
+			on_objects_changed(data);
 			_level.object_editor_name_changed(data[0], _level.object_editor_name(data[0]));
 			break;
 

+ 21 - 8
tools/level_editor/sound.vala

@@ -114,14 +114,27 @@ public class Sound
 		return i;
 	}
 
-	public void send(RuntimeInstance runtime)
-	{
-		runtime.send_script(LevelEditorApi.move_object(_id
-			, local_position()
-			, local_rotation()
-			, local_scale()
-			));
-		runtime.send_script(LevelEditorApi.set_sound_range(_id, range()));
+	public static int generate_change_sound_commands(StringBuilder sb, Guid?[] object_ids, Database db)
+	{
+		int i = 0;
+		for (; i < object_ids.length; ++i) {
+			if (db.object_type(object_ids[i]) != OBJECT_TYPE_SOUND_SOURCE)
+				break;
+
+			Guid id = object_ids[i];
+			Sound sound = new Sound(db, id);
+
+			sb.append("editor_nv, editor_nq, editor_nm = Device.temp_count()");
+			sb.append(LevelEditorApi.move_object(id
+				, sound.local_position()
+				, sound.local_rotation()
+				, sound.local_scale()
+				));
+			sb.append(LevelEditorApi.set_sound_range(id, sound.range()));
+			sb.append("Device.set_temp_count(editor_nv, editor_nq, editor_nm)");
+		}
+
+		return i;
 	}
 }
 

+ 80 - 56
tools/level_editor/unit.vala

@@ -634,67 +634,91 @@ public class Unit
 		return i;
 	}
 
-	public void send_component(RuntimeInstance runtime, Guid unit_id, Guid component_id)
+	public static int generate_change_commands(StringBuilder sb, Guid?[] object_ids, Database db)
 	{
-		string component_type = _db.object_type(component_id);
-		Unit unit = new Unit(_db, unit_id);
+		int i;
 
-		if (component_type == OBJECT_TYPE_TRANSFORM) {
-			runtime.send_script(LevelEditorApi.move_object(unit_id
-				, unit.get_component_property_vector3   (component_id, "data.position")
-				, unit.get_component_property_quaternion(component_id, "data.rotation")
-				, unit.get_component_property_vector3   (component_id, "data.scale")
-				));
-		} else if (component_type == OBJECT_TYPE_CAMERA) {
-			runtime.send_script(LevelEditorApi.set_camera(unit_id
-				, unit.get_component_property_string(component_id, "data.projection")
-				, unit.get_component_property_double(component_id, "data.fov")
-				, unit.get_component_property_double(component_id, "data.far_range")
-				, unit.get_component_property_double(component_id, "data.near_range")
-				));
-		} else if (component_type == OBJECT_TYPE_MESH_RENDERER) {
-			runtime.send_script(LevelEditorApi.set_mesh(unit_id
-				, unit.get_component_property_string(component_id, "data.mesh_resource")
-				, unit.get_component_property_string(component_id, "data.geometry_name")
-				, unit.get_component_property_string(component_id, "data.material")
-				, unit.get_component_property_bool  (component_id, "data.visible")
-				));
-		} else if (component_type == OBJECT_TYPE_SPRITE_RENDERER) {
-			runtime.send_script(LevelEditorApi.set_sprite(unit_id
-				, unit.get_component_property_string(component_id, "data.sprite_resource")
-				, unit.get_component_property_string(component_id, "data.material")
-				, unit.get_component_property_double(component_id, "data.layer")
-				, unit.get_component_property_double(component_id, "data.depth")
-				, unit.get_component_property_bool  (component_id, "data.visible")
-				));
-		} else if (component_type == OBJECT_TYPE_LIGHT) {
-			runtime.send_script(LevelEditorApi.set_light(unit_id
-				, unit.get_component_property_string (component_id, "data.type")
-				, unit.get_component_property_double (component_id, "data.range")
-				, unit.get_component_property_double (component_id, "data.intensity")
-				, unit.get_component_property_double (component_id, "data.spot_angle")
-				, unit.get_component_property_vector3(component_id, "data.color")
-				));
-		} else if (component_type == OBJECT_TYPE_SCRIPT) {
-			/* No sync. */
-		} else if (component_type == OBJECT_TYPE_COLLIDER) {
-			/* No sync. */
-		} else if (component_type == OBJECT_TYPE_ACTOR) {
-			/* No sync. */
-		} else if (component_type == OBJECT_TYPE_ANIMATION_STATE_MACHINE) {
-			/* No sync. */
+		if (object_ids.length > 1 && Unit.is_component(object_ids[1], db)) {
+			for (i = 1; i < object_ids.length; ++i) {
+				if (!is_component(object_ids[i], db))
+					break;
+
+				Guid unit_id = object_ids[0];
+				Guid component_id = object_ids[i];
+				string component_type = db.object_type(component_id);
+				Unit unit = new Unit(db, unit_id);
+
+				sb.append("editor_nv, editor_nq, editor_nm = Device.temp_count()");
+
+				if (component_type == OBJECT_TYPE_TRANSFORM) {
+					sb.append(LevelEditorApi.move_object(unit_id
+						, unit.get_component_property_vector3   (component_id, "data.position")
+						, unit.get_component_property_quaternion(component_id, "data.rotation")
+						, unit.get_component_property_vector3   (component_id, "data.scale")
+						));
+				} else if (component_type == OBJECT_TYPE_CAMERA) {
+					sb.append(LevelEditorApi.set_camera(unit_id
+						, unit.get_component_property_string(component_id, "data.projection")
+						, unit.get_component_property_double(component_id, "data.fov")
+						, unit.get_component_property_double(component_id, "data.far_range")
+						, unit.get_component_property_double(component_id, "data.near_range")
+						));
+				} else if (component_type == OBJECT_TYPE_MESH_RENDERER) {
+					sb.append(LevelEditorApi.set_mesh(unit_id
+						, unit.get_component_property_string(component_id, "data.mesh_resource")
+						, unit.get_component_property_string(component_id, "data.geometry_name")
+						, unit.get_component_property_string(component_id, "data.material")
+						, unit.get_component_property_bool  (component_id, "data.visible")
+						));
+				} else if (component_type == OBJECT_TYPE_SPRITE_RENDERER) {
+					sb.append(LevelEditorApi.set_sprite(unit_id
+						, unit.get_component_property_string(component_id, "data.sprite_resource")
+						, unit.get_component_property_string(component_id, "data.material")
+						, unit.get_component_property_double(component_id, "data.layer")
+						, unit.get_component_property_double(component_id, "data.depth")
+						, unit.get_component_property_bool  (component_id, "data.visible")
+						));
+				} else if (component_type == OBJECT_TYPE_LIGHT) {
+					sb.append(LevelEditorApi.set_light(unit_id
+						, unit.get_component_property_string (component_id, "data.type")
+						, unit.get_component_property_double (component_id, "data.range")
+						, unit.get_component_property_double (component_id, "data.intensity")
+						, unit.get_component_property_double (component_id, "data.spot_angle")
+						, unit.get_component_property_vector3(component_id, "data.color")
+						));
+				} else if (component_type == OBJECT_TYPE_SCRIPT) {
+					/* No sync. */
+				} else if (component_type == OBJECT_TYPE_COLLIDER) {
+					/* No sync. */
+				} else if (component_type == OBJECT_TYPE_ACTOR) {
+					/* No sync. */
+				} else if (component_type == OBJECT_TYPE_ANIMATION_STATE_MACHINE) {
+					/* No sync. */
+				} else {
+					logw("Unregistered component type `%s`".printf(component_type));
+				}
+
+				sb.append("Device.set_temp_count(editor_nv, editor_nq, editor_nm)");
+			}
 		} else {
-			logw("Unregistered component type `%s`".printf(component_type));
+			for (i = 0; i < object_ids.length; ++i) {
+				if (db.object_type(object_ids[i]) != OBJECT_TYPE_UNIT)
+					break;
+
+				Guid unit_id = object_ids[i];
+				Unit unit = new Unit(db, unit_id);
+
+				sb.append("editor_nv, editor_nq, editor_nm = Device.temp_count()");
+				sb.append(LevelEditorApi.move_object(unit_id
+					, unit.local_position()
+					, unit.local_rotation()
+					, unit.local_scale()
+					));
+				sb.append("Device.set_temp_count(editor_nv, editor_nq, editor_nm)");
+			}
 		}
-	}
 
-	public void send(RuntimeInstance runtime)
-	{
-		runtime.send_script(LevelEditorApi.move_object(_id
-			, local_position()
-			, local_rotation()
-			, local_scale()
-			));
+		return i;
 	}
 
 	public static bool is_component(Guid id, Database db)