mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Refactored script instance serialization and now the refactoring is finally finished...
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user