Basic Script reloading

+ ScriptComponent now saves script name instead of direct ScriptClass reference
+ Added ClearDictionaryAndDeleteKeys helper
+ Moved ScriptFieldType to separate file
+ _ScriptFieldMap now uses String as Key
This commit is contained in:
Simon Lübeß
2023-07-18 22:06:34 +02:00
parent e8505f6bdb
commit cd1562f372
10 changed files with 259 additions and 166 deletions
@@ -470,14 +470,14 @@ namespace GlitchyEditor.EditWindows
continue; continue;
if (ImGui.Selectable(className.ToScopeCStr!(), if (ImGui.Selectable(className.ToScopeCStr!(),
className == scriptComponent.Instance?.ScriptClass.FullName)) className == scriptComponent.ScriptClassName))
{ {
//scriptComponent.Instance = new ScriptInstance(scriptClass); //scriptComponent.Instance = new ScriptInstance(scriptClass);
// decrement refCount to 1 (scriptComponent.Instance increments its) // decrement refCount to 1 (scriptComponent.Instance increments its)
//scriptComponent.Instance.ReleaseRef(); //scriptComponent.Instance.ReleaseRef();
//ScriptEngine.InitializeInstance(entity, scriptComponent); //ScriptEngine.InitializeInstance(entity, scriptComponent);
scriptComponent.ScriptClass = scriptClass; scriptComponent.ScriptClassName = scriptClass.FullName;
ScriptEngine.CreateScriptFieldMap(entity); ScriptEngine.CreateScriptFieldMap(entity);
} }
@@ -485,6 +485,8 @@ namespace GlitchyEditor.EditWindows
ImGui.EndPopup(); ImGui.EndPopup();
} }
ScriptClass scriptClass = ScriptEngine.GetScriptClass(scriptComponent.ScriptClassName);
/*T GetFieldValue<T>() /*T GetFieldValue<T>()
{ {
return scriptComponent.Instance.GetFieldValue<T>(monoField); return scriptComponent.Instance.GetFieldValue<T>(monoField);
@@ -595,68 +597,68 @@ namespace GlitchyEditor.EditWindows
} }
} }
} }
else if (scriptComponent.ScriptClass != null) else if (scriptClass != null)
{ {
let scriptFields = ScriptEngine.GetScriptFieldMap(entity); let scriptFields = ScriptEngine.GetScriptFieldMap(entity);
for (var (name, field) in ref scriptFields) for (var (name, field) in ref scriptFields)
{ {
switch (field.Field.FieldType) switch (field.Type)
{ {
case .Bool: case .Bool:
var value = field.GetData<bool>(); var value = field.GetData<bool>();
if (ImGui.Checkbox(name.ToScopeCStr!(), &value)) if (ImGui.Checkbox(name.CStr(), &value))
field.SetData(value); field.SetData(value);
case .SByte: case .SByte:
var value = field.GetData<int8>(); var value = field.GetData<int8>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .S8, &value)) if (ImGui.DragScalar(name.CStr(), .S8, &value))
field.SetData(value); field.SetData(value);
case .Short: case .Short:
var value = field.GetData<int16>(); var value = field.GetData<int16>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .S16, &value)) if (ImGui.DragScalar(name.CStr(), .S16, &value))
field.SetData(value); field.SetData(value);
case .Int: case .Int:
var value = field.GetData<int32>(); var value = field.GetData<int32>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .S32, &value)) if (ImGui.DragScalar(name.CStr(), .S32, &value))
field.SetData(value); field.SetData(value);
case .Int2: case .Int2:
var value = field.GetData<int2>(); var value = field.GetData<int2>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .S32, &value, 2)) if (ImGui.DragScalarN(name.CStr(), .S32, &value, 2))
field.SetData(value); field.SetData(value);
case .Int3: case .Int3:
var value = field.GetData<int3>(); var value = field.GetData<int3>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .S32, &value, 3)) if (ImGui.DragScalarN(name.CStr(), .S32, &value, 3))
field.SetData(value); field.SetData(value);
case .Int4: case .Int4:
var value = field.GetData<int4>(); var value = field.GetData<int4>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .S32, &value, 4)) if (ImGui.DragScalarN(name.CStr(), .S32, &value, 4))
field.SetData(value); field.SetData(value);
case .Long: case .Long:
var value = field.GetData<int64>(); var value = field.GetData<int64>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .S64, &value)) if (ImGui.DragScalar(name.CStr(), .S64, &value))
field.SetData(value); field.SetData(value);
case .Byte: case .Byte:
var value = field.GetData<uint8>(); var value = field.GetData<uint8>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .U8, &value)) if (ImGui.DragScalar(name.CStr(), .U8, &value))
field.SetData(value); field.SetData(value);
case .UShort: case .UShort:
var value = field.GetData<uint16>(); var value = field.GetData<uint16>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .U16, &value)) if (ImGui.DragScalar(name.CStr(), .U16, &value))
field.SetData(value); field.SetData(value);
case .UInt: case .UInt:
var value = field.GetData<uint32>(); var value = field.GetData<uint32>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .U32, &value)) if (ImGui.DragScalar(name.CStr(), .U32, &value))
field.SetData(value); field.SetData(value);
case .ULong: case .ULong:
var value = field.GetData<uint64>(); var value = field.GetData<uint64>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .U64, &value)) if (ImGui.DragScalar(name.CStr(), .U64, &value))
field.SetData(value); field.SetData(value);
case .Float: case .Float:
var value = field.GetData<float>(); var value = field.GetData<float>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .Float, &value)) if (ImGui.DragScalar(name.CStr(), .Float, &value))
field.SetData(value); field.SetData(value);
case .float2: case .float2:
var value = field.GetData<float2>(); var value = field.GetData<float2>();
@@ -673,19 +675,19 @@ namespace GlitchyEditor.EditWindows
case .Double: case .Double:
var value = field.GetData<double>(); var value = field.GetData<double>();
if (ImGui.DragScalar(name.ToScopeCStr!(), .Double, &value)) if (ImGui.DragScalar(name.CStr(), .Double, &value))
field.SetData(value); field.SetData(value);
case .Double2: case .Double2:
var value = field.GetData<double2>(); var value = field.GetData<double2>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .Double, &value, 2)) if (ImGui.DragScalarN(name.CStr(), .Double, &value, 2))
field.SetData(value); field.SetData(value);
case .Double3: case .Double3:
var value = field.GetData<double3>(); var value = field.GetData<double3>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .Double, &value, 3)) if (ImGui.DragScalarN(name.CStr(), .Double, &value, 3))
field.SetData(value); field.SetData(value);
case .Double4: case .Double4:
var value = field.GetData<double4>(); var value = field.GetData<double4>();
if (ImGui.DragScalarN(name.ToScopeCStr!(), .Double, &value, 4)) if (ImGui.DragScalarN(name.CStr(), .Double, &value, 4))
field.SetData(value); field.SetData(value);
case .Enum: case .Enum:
@@ -701,7 +703,7 @@ namespace GlitchyEditor.EditWindows
// TODO! // TODO!
default: default:
Log.EngineLogger.Error($"Unhandled field type {field.Field.FieldType}"); Log.EngineLogger.Error($"Unhandled field type {field.Type}");
} }
} }
} }
+10
View File
@@ -13,6 +13,7 @@ using GlitchyEngine.Renderer.Animation;
using System.IO; using System.IO;
using GlitchyEngine.Core; using GlitchyEngine.Core;
using GlitchyEditor.Assets; using GlitchyEditor.Assets;
using GlitchyEngine.Scripting;
namespace GlitchyEditor namespace GlitchyEditor
{ {
@@ -730,6 +731,15 @@ namespace GlitchyEditor
ImGui.EndMenu(); ImGui.EndMenu();
} }
if(ImGui.BeginMenu("Tools", true))
{
if(ImGui.MenuItem("Reload Scripts"))
ScriptEngine.ReloadAssemblies();
ImGui.EndMenu();
}
ImGui.EndMainMenuBar(); ImGui.EndMainMenuBar();
} }
+10
View File
@@ -60,5 +60,15 @@ namespace GlitchyEngine
delete container; delete container;
} }
} }
public static mixin ClearDictionaryAndDeleteKeys(var dictionary)
{
if (dictionary != null)
{
for (var value in dictionary)
delete value.key;
delete dictionary;
}
}
} }
} }
+4 -4
View File
@@ -25,13 +25,13 @@ public struct ScriptField
public struct ScriptFieldInstance public struct ScriptFieldInstance
{ {
public ScriptField Field; public ScriptFieldType Type;
// TODO: I hate this, but we need to be able to store an entire matrix // TODO: I hate this, but we need to be able to store an entire matrix
internal uint8[sizeof(GlitchyEngine.Math.Matrix)] _data; internal uint8[sizeof(GlitchyEngine.Math.Matrix)] _data;
public this(ScriptField field) public this(ScriptFieldType type)
{ {
Field = field; Type = type;
_data = default; _data = default;
} }
@@ -47,7 +47,7 @@ public struct ScriptFieldInstance
} }
} }
public typealias ScriptFieldMap = Dictionary<StringView, ScriptFieldInstance>; public typealias ScriptFieldMap = Dictionary<String, ScriptFieldInstance>;
abstract class SharpType : RefCounter abstract class SharpType : RefCounter
{ {
+75 -104
View File
@@ -2,100 +2,14 @@ using Mono;
using System; using System;
using System.IO; using System.IO;
using System.Collections; using System.Collections;
using GlitchyEngine.Core;
using GlitchyEngine.Math; using GlitchyEngine.Math;
using GlitchyEngine.World; using GlitchyEngine.World;
using GlitchyEngine.Core;
namespace GlitchyEngine.Scripting; namespace GlitchyEngine.Scripting;
using internal GlitchyEngine.Scripting; using internal GlitchyEngine.Scripting;
enum ScriptFieldType
{
None,
Class,
Enum,
Struct,
// TODO!
Bool,
SByte,
Short,
Int, Int2, Int3, Int4,
Long,
Byte,
UShort,
UInt, // UInt2, UInt3, UInt4,
ULong,
// Half, Half2, Half3, Half4,
Float, float2, float3, float4,
Double, Double2, Double3, Double4,
Entity
}
extension ScriptFieldType
{
public Type GetBeefType()
{
switch(this)
{
case .Bool:
return typeof(bool);
case .SByte:
return typeof(int8);
case .Short:
return typeof(int16);
case .Int:
return typeof(int32);
case .Int2:
return typeof(int2);
case .Int3:
return typeof(int3);
case .Int4:
return typeof(int4);
case .Long:
return typeof(int64);
case .Byte:
return typeof(uint8);
case .UShort:
return typeof(uint16);
case .UInt:
return typeof(uint32);
case .ULong:
return typeof(uint64);
case .Float:
return typeof(float);
case .float2:
return typeof(float2);
case .float3:
return typeof(float3);
case .float4:
return typeof(float4);
case .Double:
return typeof(double);
case .Double2:
return typeof(double2);
case .Double3:
return typeof(double3);
case .Double4:
return typeof(double4);
case .Entity:
return typeof(UUID);
default:
return null;
}
}
}
static sealed class ScriptEngineHelper static sealed class ScriptEngineHelper
{ {
private static Dictionary<StringView, ScriptFieldType> _scriptFieldTypes = new Dictionary<StringView, ScriptFieldType>() private static Dictionary<StringView, ScriptFieldType> _scriptFieldTypes = new Dictionary<StringView, ScriptFieldType>()
@@ -163,7 +77,15 @@ static class ScriptEngine
public static Scene Context => s_Context; public static Scene Context => s_Context;
private static Dictionary<UUID, ScriptFieldMap> _entityFields = new .() ~ DeleteDictionaryAndValues!(_); private static Dictionary<UUID, ScriptFieldMap> _entityFields = new .() ~
{
for (var value in _entityFields.Values)
{
DeleteDictionaryAndKeys!(value);
}
delete _;
};
internal static class Attributes internal static class Attributes
{ {
@@ -179,6 +101,11 @@ static class ScriptEngine
ScriptGlue.Init(); ScriptGlue.Init();
LoadScriptAssemblies();
}
static void LoadScriptAssemblies()
{
CreateAppDomain("GlitchyEngineScriptRuntime"); CreateAppDomain("GlitchyEngineScriptRuntime");
(s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll"); (s_CoreAssembly, s_CoreAssemblyImage) = LoadAssembly("resources/scripts/ScriptCore.dll");
(s_AppAssembly, s_AppAssemblyImage) = LoadAssembly("SandboxProject/Assets/Scripts/bin/Sandbox.dll"); (s_AppAssembly, s_AppAssemblyImage) = LoadAssembly("SandboxProject/Assets/Scripts/bin/Sandbox.dll");
@@ -186,8 +113,6 @@ static class ScriptEngine
GetEntitiesFromAssemblies(); GetEntitiesFromAssemblies();
ScriptGlue.RegisterManagedComponents(); ScriptGlue.RegisterManagedComponents();
//Samples();
} }
public static void SetContext(Scene scene) public static void SetContext(Scene scene)
@@ -206,26 +131,38 @@ static class ScriptEngine
SetContext(null); SetContext(null);
} }
public static void InitializeInstance(Entity entity, ScriptComponent* script) public static bool InitializeInstance(Entity entity, ScriptComponent* script)
{ {
ScriptClass scriptClass = GetScriptClass(script.ScriptClassName);
if (scriptClass == null)
return false;
script.Instance = new ScriptInstance(scriptClass);
script.Instance..ReleaseRef();
_entityScriptInstances[entity.UUID] = script.Instance..AddRef(); _entityScriptInstances[entity.UUID] = script.Instance..AddRef();
script.Instance.Instantiate(entity.UUID); script.Instance.Instantiate(entity.UUID);
CopyEditorFieldsToInstance(entity, script); CopyEditorFieldsToInstance(entity, script);
return true;
} }
private static void CopyEditorFieldsToInstance(Entity entity, ScriptComponent* script) private static void CopyEditorFieldsToInstance(Entity entity, ScriptComponent* script)
{ {
// Technically the map is for a different entity (namely the editor-entity), // Technically the map is for a different entity (namely the editor-entity),
// however the UUID is the same, so we get the correct field map // however the UUID is the same, so we get the correct field map
let fiels = GetScriptFieldMap(entity); let fields = GetScriptFieldMap(entity);
for (var (fieldName, field) in fiels) for (var (fieldName, field) in fields)
{ {
// TODO: a litte assertion maybe? // TODO: a litte assertion maybe?
script.Instance.SetFieldValue(field.Field, field._data); ScriptField scriptField = script.Instance.ScriptClass.Fields[fieldName];
script.Instance.SetFieldValue(scriptField, field._data);
} }
} }
@@ -278,13 +215,22 @@ static class ScriptEngine
} }
_entityScripts.Clear(); _entityScripts.Clear();
if (s_EngineObject == null) for (var sharpClass in _sharpClasses)
{ {
sharpClass.value.ReleaseRef();
}
_sharpClasses.Clear();
if (s_EngineObject != null)
{
s_EngineObject.ReleaseRef();
s_EntityRoot.ReleaseRef();
}
s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", s_CoreAssemblyImage); s_EngineObject = new ScriptClass("GlitchyEngine.Core", "EngineObject", s_CoreAssemblyImage);
s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", s_CoreAssemblyImage); s_EntityRoot = new ScriptClass("GlitchyEngine", "Entity", s_CoreAssemblyImage);
Log.EngineLogger.Assert(s_EntityRoot != null); Log.EngineLogger.Assert(s_EntityRoot != null);
}
Attributes.s_ShowInEditorAttribute = Mono.mono_class_from_name(s_CoreAssemblyImage, "GlitchyEngine.Editor", "ShowInEditorAttribute"); Attributes.s_ShowInEditorAttribute = Mono.mono_class_from_name(s_CoreAssemblyImage, "GlitchyEngine.Editor", "ShowInEditorAttribute");
@@ -311,13 +257,28 @@ static class ScriptEngine
} }
} }
public static void Shutdown() public static void ReloadAssemblies()
{ {
/*Mono.mono_assembly_close(s_CoreAssembly); Mono.mono_domain_set(s_RootDomain, false);
s_CoreAssembly = null;
Mono.mono_domain_unload(s_AppDomain); Mono.mono_domain_unload(s_AppDomain);
s_AppDomain = null;*/
LoadScriptAssemblies();
// TODO: ScriptFields might get added
// TODO: ScriptField Types may change after reload!
// TODO: Scripts may be renamed (probably not detectable (trivially))
// TODO: Reload in play mode
// Only scripts that were changed should actually be reinstatiated
}
public static void Shutdown()
{
Mono.mono_domain_set(s_RootDomain, false);
Mono.mono_domain_unload(s_AppDomain);
s_AppDomain = null;
Mono.mono_jit_cleanup(s_RootDomain); Mono.mono_jit_cleanup(s_RootDomain);
s_RootDomain = null; s_RootDomain = null;
@@ -375,19 +336,23 @@ static class ScriptEngine
if (_entityFields.TryGetValue(entity.UUID, var entityFields)) if (_entityFields.TryGetValue(entity.UUID, var entityFields))
{ {
entityFields.Clear(); ClearDictionaryAndDeleteKeys!(entityFields);
} }
else else
{ {
entityFields = new Dictionary<StringView, ScriptFieldInstance>(); entityFields = new ScriptFieldMap();
_entityFields.Add(entity.UUID, entityFields); _entityFields.Add(entity.UUID, entityFields);
} }
let scriptComponent = entity.GetComponent<ScriptComponent>(); let scriptComponent = entity.GetComponent<ScriptComponent>();
for (let (fieldName, field) in scriptComponent.ScriptClass.Fields) ScriptClass scriptClass = GetScriptClass(scriptComponent.ScriptClassName);
Log.EngineLogger.AssertDebug(scriptClass != null);
for (let (fieldName, field) in scriptClass.Fields)
{ {
entityFields.Add(fieldName, ScriptFieldInstance(field)); entityFields.Add(new String(fieldName), ScriptFieldInstance(field.FieldType));
} }
} }
@@ -411,6 +376,12 @@ static class ScriptEngine
return null; return null;
} }
public static ScriptClass GetScriptClass(StringView name)
{
EntityClasses.TryGetValue(name, let scriptClass);
return scriptClass;
}
@@ -0,0 +1,87 @@
using System;
using GlitchyEngine.Core;
using GlitchyEngine.Math;
namespace GlitchyEngine.Scripting;
enum ScriptFieldType
{
case None;
case Class;
case Enum;
case Struct;
case Bool;
case SByte;
case Short;
case Int, Int2, Int3, Int4;
case Long;
case Byte;
case UShort;
case UInt; // UInt2, UInt3, UInt4;
case ULong;
case Float, float2, float3, float4;
case Double, Double2, Double3, Double4;
case Entity;
public Type GetBeefType()
{
switch(this)
{
case .Bool:
return typeof(bool);
case .SByte:
return typeof(int8);
case .Short:
return typeof(int16);
case .Int:
return typeof(int32);
case .Int2:
return typeof(int2);
case .Int3:
return typeof(int3);
case .Int4:
return typeof(int4);
case .Long:
return typeof(int64);
case .Byte:
return typeof(uint8);
case .UShort:
return typeof(uint16);
case .UInt:
return typeof(uint32);
case .ULong:
return typeof(uint64);
case .Float:
return typeof(float);
case .float2:
return typeof(float2);
case .float3:
return typeof(float3);
case .float4:
return typeof(float4);
case .Double:
return typeof(double);
case .Double2:
return typeof(double2);
case .Double3:
return typeof(double3);
case .Double4:
return typeof(double4);
case .Entity:
return typeof(UUID);
default:
return null;
}
}
}
@@ -57,6 +57,10 @@ static class ScriptGlue
public static void RegisterManagedComponents() public static void RegisterManagedComponents()
{ {
s_AddComponentMethods.Clear();
s_HasComponentMethods.Clear();
s_RemoveComponentMethods.Clear();
RegisterComponent<TransformComponent>("GlitchyEngine.Transform"); RegisterComponent<TransformComponent>("GlitchyEngine.Transform");
RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.RigidBody2D"); RegisterComponent<Rigidbody2DComponent>("GlitchyEngine.RigidBody2D");
} }
@@ -507,14 +507,20 @@ namespace GlitchyEngine.World
struct ScriptComponent : IDisposableComponent struct ScriptComponent : IDisposableComponent
{ {
private ScriptClass _scriptClass = null; private String _scriptClassName = null;
private ScriptInstance _instance = null; private ScriptInstance _instance = null;
public ScriptClass ScriptClass public StringView ScriptClassName
{ {
get => _scriptClass; get => _scriptClassName;
set mut => SetReference!(_scriptClass, value); set mut
{
if (_scriptClassName == null)
_scriptClassName = new String(value);
_scriptClassName.Set(value);
}
} }
public ScriptInstance Instance public ScriptInstance Instance
@@ -525,16 +531,13 @@ namespace GlitchyEngine.World
set mut => SetReference!(_instance, value); set mut => SetReference!(_instance, value);
} }
/// Gets whether or not this script component has a script assigned (that means ScriptClass isn't null).
public bool HasScript => _scriptClass != null;
public bool IsInitialized => _instance?.IsInitialized ?? false; public bool IsInitialized => _instance?.IsInitialized ?? false;
public bool IsCreated => _instance?.IsCreated ?? false; public bool IsCreated => _instance?.IsCreated ?? false;
public void Dispose() mut public void Dispose() mut
{ {
ReleaseRefAndNullify!(_scriptClass); delete _scriptClassName;
ReleaseRefAndNullify!(_instance); ReleaseRefAndNullify!(_instance);
} }
} }
+2 -3
View File
@@ -93,11 +93,10 @@ namespace GlitchyEngine.World
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID); Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
ScriptComponent* targetComponent = targetEntity.AddComponent<ScriptComponent>(); ScriptComponent* targetComponent = targetEntity.AddComponent<ScriptComponent>();
targetComponent.ScriptClass = sourceComponent.ScriptClass; targetComponent.ScriptClassName = sourceComponent.ScriptClassName;
targetComponent.Instance = new ScriptInstance(sourceComponent.ScriptClass);
targetComponent.Instance..ReleaseRef();
// 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.
ScriptEngine.InitializeInstance(targetEntity, targetComponent); ScriptEngine.InitializeInstance(targetEntity, targetComponent);
} }
+26 -19
View File
@@ -189,9 +189,11 @@ class SceneSerializer
SerializeComponent<ScriptComponent>(writer, entity, "ScriptComponent", scope (component) => SerializeComponent<ScriptComponent>(writer, entity, "ScriptComponent", scope (component) =>
{ {
Serialize.Value(writer, "ScriptClass", component.ScriptClass?.FullName); Serialize.Value(writer, "ScriptClass", component.ScriptClassName);
if (component.HasScript) //if (component.HasScript)
// TODO: Thats not a good check, I think. At least we know the script class is valid
if (ScriptEngine.GetScriptClass(component.ScriptClassName) != null)
{ {
let fields = ScriptEngine.GetScriptFieldMap(entity); let fields = ScriptEngine.GetScriptFieldMap(entity);
@@ -201,11 +203,10 @@ class SceneSerializer
{ {
for (var (fieldName, fieldInstance) in fields) for (var (fieldName, fieldInstance) in fields)
{ {
if (fieldInstance.Field.FieldType == .None) if (fieldInstance.Type == .None)
continue; continue;
switch (fieldInstance.Type)
switch (fieldInstance.Field.FieldType)
{ {
case .Enum, .Class, .Struct: case .Enum, .Class, .Struct:
// TODO: implement // TODO: implement
@@ -213,10 +214,10 @@ class SceneSerializer
writer.Identifier(fieldName); writer.Identifier(fieldName);
String str = scope .(); String str = scope .();
fieldInstance.Field.FieldType.ToString(str); fieldInstance.Type.ToString(str);
writer.Type(str); writer.Type(str);
Serialize.Value(writer, ValueView(fieldInstance.Field.FieldType.GetBeefType(), &fieldInstance.[Friend]_data), gBonEnv); Serialize.Value(writer, ValueView(fieldInstance.Type.GetBeefType(), &fieldInstance.[Friend]_data), gBonEnv);
} }
} }
} }
@@ -558,15 +559,18 @@ class SceneSerializer
if (scriptClassName != null) if (scriptClassName != null)
{ {
if (ScriptEngine.EntityClasses.TryGetValue(scriptClassName, let scriptClass)) //if (ScriptEngine.EntityClasses.TryGetValue(scriptClassName, let scriptClass))
{ /*{
component.ScriptClass = scriptClass; component.ScriptClass = scriptClass;
} }*/
component.ScriptClassName = scriptClassName;
delete scriptClassName; delete scriptClassName;
} }
if (component.HasScript) //if (component.HasScript)
if (ScriptEngine.GetScriptClass(component.ScriptClassName) != null)
{ {
// This whole operation is technically a bit junk, because we are not guaranteed to successfully deserialize the scene, // This whole operation is technically a bit junk, because we are not guaranteed to successfully deserialize the scene,
// however we are editing the ScriptEngine because it doesn't care about which scene is active right now. // however we are editing the ScriptEngine because it doesn't care about which scene is active right now.
@@ -606,15 +610,18 @@ class SceneSerializer
StringView fieldName = Try!(reader.Identifier()); StringView fieldName = Try!(reader.Identifier());
if (fields.ContainsKey(fieldName)) // Allocate a string on the stack, because the dictionary uses a string as key
String fieldNameString = scope .(fieldName);
if (fields.ContainsKey(fieldNameString))
{ {
var field = ref fields[fieldName]; var field = ref fields[fieldNameString];
Result<StringView> fieldTypeName = reader.Type(); Result<StringView> fieldTypeName = reader.Type();
if (fieldTypeName case .Err) if (fieldTypeName case .Err)
{ {
Log.EngineLogger.Error($"Failed to read field type for field \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")"); Log.EngineLogger.Error($"Failed to read field type for field \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1); reader.FileEntrySkip(1);
dontRemoveComma = true; dontRemoveComma = true;
continue; continue;
@@ -622,9 +629,9 @@ class SceneSerializer
Result<ScriptFieldType> fieldType = Enum.Parse<ScriptFieldType>(fieldTypeName, true); Result<ScriptFieldType> fieldType = Enum.Parse<ScriptFieldType>(fieldTypeName, true);
if ((fieldType case .Err) || (fieldType != field.Field.FieldType)) if ((fieldType case .Err) || (fieldType != field.Type))
{ {
Log.EngineLogger.Error($"Unexpected field type (\"{fieldTypeName}\" instead of \"{field.Field.FieldType}\" for field: \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")"); Log.EngineLogger.Error($"Unexpected field type (\"{fieldTypeName}\" instead of \"{field.Type}\" for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1); reader.FileEntrySkip(1);
dontRemoveComma = true; dontRemoveComma = true;
continue; continue;
@@ -632,9 +639,9 @@ class SceneSerializer
void* data = &field.[Friend]_data; void* data = &field.[Friend]_data;
if (Deserialize.Value(reader, ValueView(field.Field.FieldType.GetBeefType(), data), gBonEnv) case .Err) if (Deserialize.Value(reader, ValueView(field.Type.GetBeefType(), data), gBonEnv) case .Err)
{ {
Log.EngineLogger.Error($"Failed to deserialize data for field: \"{fieldName}\" in script \"{component.ScriptClass.FullName}\" of entity {entity.UUID} (\"{entity.Name}\")"); Log.EngineLogger.Error($"Failed to deserialize data for field: \"{fieldName}\" in script \"{component.ScriptClassName}\" of entity {entity.UUID} (\"{entity.Name}\")");
reader.FileEntrySkip(1); reader.FileEntrySkip(1);
dontRemoveComma = true; dontRemoveComma = true;
continue; continue;
@@ -642,7 +649,7 @@ class SceneSerializer
} }
else else
{ {
Log.EngineLogger.Error($"Script \"{component.ScriptClass.FullName}\" doesn't have a field with name \"{fieldName}\". (Entity {entity.UUID} (\"{entity.Name}\"))"); Log.EngineLogger.Error($"Script \"{component.ScriptClassName}\" doesn't have a field with name \"{fieldName}\". (Entity {entity.UUID} (\"{entity.Name}\"))");
} }
} }