Refactored script instance serialization and now the refactoring is finally finished...

This commit is contained in:
Simon Lübeß
2024-04-10 14:42:07 +02:00
parent 95262d67d7
commit d81471419d
5 changed files with 127 additions and 100 deletions
+10 -17
View File
@@ -811,14 +811,14 @@ namespace GlitchyEditor
ImGui.FocusWindow(window); ImGui.FocusWindow(window);
} }
append Dictionary<UUID, SerializedObject> _prePlaySerializedData = .() ~ ClearDictionaryAndDeleteValues!(_prePlaySerializedData); append ScriptInstanceSerializer _scriptSerializer = .();
/// Starts the play mode for the current scene /// Starts the play mode for the current scene
private void OnScenePlay() private void OnScenePlay()
{ {
Log.EngineLogger.AssertDebug(_prePlaySerializedData.Count == 0, "Somehow some entities are serialized."); Log.EngineLogger.AssertDebug(_scriptSerializer.SerializedObjectCount == 0, "Somehow some entities are serialized.");
ScriptEngine.SerializeScriptInstances(_prePlaySerializedData); _scriptSerializer.SerializeScriptInstances();
_editor.SceneViewportWindow.EditorMode = false; _editor.SceneViewportWindow.EditorMode = false;
_sceneState = .Play; _sceneState = .Play;
@@ -829,7 +829,7 @@ namespace GlitchyEditor
SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true, newPlayMode: .Play); SetActiveScene(runtimeScene, startRuntime: true, startSimulation: true, newPlayMode: .Play);
ScriptEngine.DeserializeScriptInstances(_prePlaySerializedData); _scriptSerializer.DeserializeScriptInstances();
} }
_editor.CurrentScene = _activeScene; _editor.CurrentScene = _activeScene;
@@ -947,22 +947,15 @@ namespace GlitchyEditor
SwitchToEditorWindow(); SwitchToEditorWindow();
// Reconstruct state before play // Reconstruct state before play
ScriptEngine.DeserializeScriptInstances(_prePlaySerializedData); _scriptSerializer.DeserializeScriptInstances();
_scriptSerializer.Clear();
ClearPrePlaySerializedData();
}
/// Clears the serialized data cache.
private void ClearPrePlaySerializedData()
{
ClearDictionaryAndDeleteValues!(_prePlaySerializedData);
} }
/// Stops the scene and cleans up the subsystems to allow loading another scene. /// Stops the scene and cleans up the subsystems to allow loading another scene.
private void CloseCurrentScene() private void CloseCurrentScene()
{ {
// Clear serialized data, so that we don't waste time deserializing it. // Clear serialized data, so that we don't waste time deserializing it.
ClearPrePlaySerializedData(); _scriptSerializer.Clear();
OnSceneStop(); OnSceneStop();
} }
@@ -983,7 +976,7 @@ namespace GlitchyEditor
} }
/// Sets the current editor scene /// Sets the current editor scene
private void SetEditorScene(Scene scene, Dictionary<UUID, SerializedObject> serializedObjects = null) private void SetEditorScene(Scene scene, ScriptInstanceSerializer serializedObjects = null)
{ {
_editorScene?.Stop(); _editorScene?.Stop();
@@ -998,7 +991,7 @@ namespace GlitchyEditor
if (serializedObjects != null) if (serializedObjects != null)
{ {
// Reconstruct state // Reconstruct state
ScriptEngine.DeserializeScriptInstances(serializedObjects); serializedObjects.DeserializeScriptInstances();
} }
} }
@@ -1118,7 +1111,7 @@ namespace GlitchyEditor
// Make sure we actually loaded something! // Make sure we actually loaded something!
if (result case .Ok) if (result case .Ok)
{ {
SetEditorScene(newScene, serializer.SerializedObjects); SetEditorScene(newScene, serializer.ScriptSerializer);
String relativePath = scope .(); String relativePath = scope .();
Path.GetRelativePath(filename, _currentProject.WorkspacePath, relativePath); Path.GetRelativePath(filename, _currentProject.WorkspacePath, relativePath);
+4 -65
View File
@@ -96,7 +96,7 @@ static class ScriptEngine
private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndReleaseValues!(_); private static Dictionary<StringView, ScriptClass> _entityScripts = new .() ~ DeleteDictionaryAndReleaseValues!(_);
private static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ { internal static Dictionary<UUID, ScriptInstance> _entityScriptInstances = new .() ~ {
for (var entry in _) for (var entry in _)
{ {
entry.value?.ReleaseRef(); entry.value?.ReleaseRef();
@@ -485,9 +485,9 @@ static class ScriptEngine
Log.EngineLogger.Info("Reloading script assemblies."); Log.EngineLogger.Info("Reloading script assemblies.");
Dictionary<UUID, SerializedObject> serializedData = scope .(); ScriptInstanceSerializer contextSerializer = scope .();
SerializeScriptInstances(serializedData); contextSerializer.SerializeScriptInstances();
Mono.mono_domain_set(s_RootDomain, true); Mono.mono_domain_set(s_RootDomain, true);
@@ -513,9 +513,7 @@ static class ScriptEngine
} }
} }
DeserializeScriptInstances(serializedData); contextSerializer.DeserializeScriptInstances();
ClearDictionaryAndDeleteValues!(serializedData);
Log.EngineLogger.Info("Script assemblies reloaded!"); Log.EngineLogger.Info("Script assemblies reloaded!");
} }
@@ -582,63 +580,4 @@ static class ScriptEngine
Classes.EntityEditor.ShowEntityEditor(scriptComponent.Instance, entity.UUID); Classes.EntityEditor.ShowEntityEditor(scriptComponent.Instance, entity.UUID);
} }
/// Serializes all script instances
public static void SerializeScriptInstances(Dictionary<UUID, SerializedObject> allObjects)
{
Debug.Profiler.ProfileFunction!();
for (let (id, script) in _entityScriptInstances)
{
SerializeScriptInstance(script, allObjects);
}
}
/// Serializes the given script instance
public static void SerializeScriptInstance(ScriptInstance script, Dictionary<UUID, SerializedObject> allObjects)
{
SerializedObject object = new SerializedObject(allObjects, script.ScriptClass.FullName, script.EntityId);
object.Serialize(script);
}
/// Deserializes the given data into the script instances
public static void DeserializeScriptInstances(Dictionary<UUID, SerializedObject> allObjects)
{
Debug.Profiler.ProfileFunction!();
for (let (id, script) in _entityScriptInstances)
{
DeserializeScriptInstance(id, script, allObjects);
}
}
/// Deserializes the given script instance.
/// @returns true if the script had serialized data; false otherwise.
public static bool DeserializeScriptInstance(UUID id, ScriptInstance script, Dictionary<UUID, SerializedObject> allObjects)
{
if (allObjects.TryGetValue(id, let object))
{
object.Deserialize(script);
return true;
}
return false;
}
/// Replaces Entity references in the given serialized data using the specified translation table.
public static void FixupSerializedIds(Dictionary<UUID, UUID> originalToCopyIds, Dictionary<UUID, SerializedObject> allObjects)
{
for (let (id, object) in allObjects)
{
for (var fieldData in ref object.Fields.Values)
{
if (fieldData.PrimitiveType != .EntityReference && fieldData.PrimitiveType != .ComponentReference)
continue;
if (originalToCopyIds.TryGetValue(fieldData.Data.EngineObject.ID, let copyId))
fieldData.Data.EngineObject.ID = copyId;
}
}
}
} }
@@ -0,0 +1,97 @@
using System.Collections;
using GlitchyEngine.Core;
using GlitchyEngine.Serialization;
namespace GlitchyEngine.Scripting;
using internal GlitchyEngine.Scripting;
/// Provides capability to serialize and deserialize C# objects managed by the script engine
public class ScriptInstanceSerializer
{
append Dictionary<UUID, SerializedObject> _serializedData = .();
public int SerializedObjectCount => _serializedData.Count;
public Dictionary<UUID, SerializedObject> SerializedObjects => _serializedData;
public ~this()
{
Clear();
delete:append _serializedData;
}
public void Clear()
{
ClearDictionaryAndDeleteValues!(_serializedData);
}
/// Serializes all script instances that are currently managed by the ScriptEngine.
public void SerializeScriptInstances()
{
Debug.Profiler.ProfileFunction!();
for (let (id, script) in ScriptEngine._entityScriptInstances)
{
SerializeScriptInstance(script);
}
}
/// Serializes the given script instance.
public void SerializeScriptInstance(ScriptInstance script)
{
SerializedObject object = new SerializedObject(_serializedData, script.ScriptClass.FullName, script.EntityId);
object.Serialize(script);
}
/// Deserializes this context into the instances currently managed by the script engine.
public void DeserializeScriptInstances()
{
Debug.Profiler.ProfileFunction!();
for (let (id, script) in ScriptEngine._entityScriptInstances)
{
DeserializeScriptInstance(id, script);
}
}
/// Deserializes the data into the given script instance, if there is data available.
/// @returns true if the script had serialized data; false otherwise.
public bool DeserializeScriptInstance(UUID id, ScriptInstance script)
{
if (_serializedData.TryGetValue(id, let object))
{
object.Deserialize(script);
return true;
}
return false;
}
/// Replaces Entity references in the given serialized data using the specified translation table.
public void FixupSerializedIds(Dictionary<UUID, UUID> originalToCopyIds)
{
for (let (id, object) in _serializedData)
{
for (var fieldData in ref object.Fields.Values)
{
if (fieldData.PrimitiveType != .EntityReference && fieldData.PrimitiveType != .ComponentReference)
continue;
if (originalToCopyIds.TryGetValue(fieldData.Data.EngineObject.ID, let copyId))
fieldData.Data.EngineObject.ID = copyId;
}
}
}
public SerializedObject GetSerializedObject(UUID id)
{
return _serializedData[id];
}
public bool TryGetSerializedObject(UUID id, out SerializedObject object)
{
return _serializedData.TryGetValue(id, out object);
}
}
+6 -5
View File
@@ -958,8 +958,9 @@ namespace GlitchyEngine.World
*/ */
public Entity CreateInstance(Entity entity) public Entity CreateInstance(Entity entity)
{ {
Dictionary<UUID, SerializedObject> serializedData = scope .(); //Dictionary<UUID, SerializedObject> serializedData = scope .();
defer { ClearDictionaryAndDeleteValues!(serializedData); } ScriptInstanceSerializer scriptSerializer = scope .();
//defer { ClearDictionaryAndDeleteValues!(serializedData); }
List<Entity> newEntities = scope .(); List<Entity> newEntities = scope .();
Dictionary<EcsEntity, EcsEntity> sourceToTargetEntity = scope .(); Dictionary<EcsEntity, EcsEntity> sourceToTargetEntity = scope .();
@@ -1002,7 +1003,7 @@ namespace GlitchyEngine.World
if (sourceScript.Instance != null) if (sourceScript.Instance != null)
{ {
ScriptEngine.SerializeScriptInstance(sourceScript.Instance, serializedData); scriptSerializer.SerializeScriptInstance(sourceScript.Instance);
// Initializes the created instance // Initializes the created instance
// TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think. // TODO: this returns false, if no script with ScriptClassName exists, we have to handle this case correctly I think.
@@ -1024,13 +1025,13 @@ namespace GlitchyEngine.World
Entity newEntity = CopyEntityAndChildren(entity, null); Entity newEntity = CopyEntityAndChildren(entity, null);
// Replace old IDs with new ones // Replace old IDs with new ones
ScriptEngine.FixupSerializedIds(sourceIdToTargetId, serializedData); scriptSerializer.FixupSerializedIds(sourceIdToTargetId);
// Use separate loops for deserialization and OnCreate to ensure complete entities and references in OnCreate // Use separate loops for deserialization and OnCreate to ensure complete entities and references in OnCreate
for (let (originalId, newScriptInstance) in newScripts) for (let (originalId, newScriptInstance) in newScripts)
{ {
ScriptEngine.DeserializeScriptInstance(originalId, newScriptInstance, serializedData); scriptSerializer.DeserializeScriptInstance(originalId, newScriptInstance);
} }
for (let (_, newScriptInstance) in newScripts) for (let (_, newScriptInstance) in newScripts)
+10 -13
View File
@@ -28,11 +28,11 @@ class SceneSerializer
// Maps from ID in the prefab file to the actual ID in the scene. // Maps from ID in the prefab file to the actual ID in the scene.
private Dictionary<UUID, UUID> _fileToSceneId; private Dictionary<UUID, UUID> _fileToSceneId;
private Dictionary<UUID, SerializedObject> _serializedObjects ~ DeleteDictionaryAndValues!(_); private append ScriptInstanceSerializer _scriptSerializer = .(); //Dictionary<UUID, SerializedObject> _serializedObjects ~ DeleteDictionaryAndValues!(_);
private HashSet<UUID> _objectsNotWritten; private HashSet<UUID> _objectsNotWritten;
public Dictionary<UUID, SerializedObject> SerializedObjects => _serializedObjects; public ScriptInstanceSerializer ScriptSerializer => _scriptSerializer;
public this(Scene scene) public this(Scene scene)
{ {
@@ -43,13 +43,11 @@ class SceneSerializer
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
_serializedObjects = new .(); _scriptSerializer.SerializeScriptInstances();
ScriptEngine.SerializeScriptInstances(_serializedObjects); _objectsNotWritten = new .(_scriptSerializer.SerializedObjectCount);
_objectsNotWritten = new .(_serializedObjects.Count); for (UUID key in _scriptSerializer.SerializedObjects.Keys)
for (UUID key in _serializedObjects.Keys)
{ {
_objectsNotWritten.Add(key); _objectsNotWritten.Add(key);
} }
@@ -84,11 +82,12 @@ class SceneSerializer
writer.Identifier("ReferencedObjects"); writer.Identifier("ReferencedObjects");
// Write all objects that don't belong to an entity. (referenced Arrays, Classes, etc...)
using (writer.ArrayBlock()) using (writer.ArrayBlock())
{ {
for (UUID id in _objectsNotWritten) for (UUID id in _objectsNotWritten)
{ {
Serialize.Value(writer, _serializedObjects[id]); Serialize.Value(writer, _scriptSerializer.GetSerializedObject(id));
} }
} }
@@ -237,7 +236,7 @@ class SceneSerializer
{ {
Serialize.Value(writer, "ScriptClass", component.ScriptClassName); Serialize.Value(writer, "ScriptClass", component.ScriptClassName);
if (_serializedObjects.TryGetValue(entity.UUID, let value)) if (_scriptSerializer.TryGetSerializedObject(entity.UUID, let value))
{ {
Serialize.Value(writer, "Fields", value); Serialize.Value(writer, "Fields", value);
@@ -285,8 +284,6 @@ class SceneSerializer
{ {
Debug.Profiler.ProfileResourceFunction!(); Debug.Profiler.ProfileResourceFunction!();
_serializedObjects = new .();
_parentIdToChild = scope Dictionary<UUID, Entity>(); _parentIdToChild = scope Dictionary<UUID, Entity>();
_entitiesMissingParent = scope List<(Entity Entity, UUID ParentId)>(); _entitiesMissingParent = scope List<(Entity Entity, UUID ParentId)>();
_fileToSceneId = scope Dictionary<UUID, UUID>(); _fileToSceneId = scope Dictionary<UUID, UUID>();
@@ -344,7 +341,7 @@ class SceneSerializer
Try!(reader.EntryEnd()); Try!(reader.EntryEnd());
} }
Try!(SerializedObject.BonDeserialize(reader, _serializedObjects, gBonEnv)); Try!(SerializedObject.BonDeserialize(reader, _scriptSerializer.SerializedObjects, gBonEnv));
first = false; first = false;
} }
@@ -667,7 +664,7 @@ class SceneSerializer
Try!(reader.EntryEnd()); Try!(reader.EntryEnd());
if (Try!(reader.Identifier()) == "Fields") if (Try!(reader.Identifier()) == "Fields")
SerializedObject.BonDeserialize(reader, _serializedObjects, gBonEnv); SerializedObject.BonDeserialize(reader, _scriptSerializer.SerializedObjects, gBonEnv);
} }
return .Ok; return .Ok;