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
@@ -507,14 +507,20 @@ namespace GlitchyEngine.World
struct ScriptComponent : IDisposableComponent
{
private ScriptClass _scriptClass = null;
private String _scriptClassName = null;
private ScriptInstance _instance = null;
public ScriptClass ScriptClass
public StringView ScriptClassName
{
get => _scriptClass;
set mut => SetReference!(_scriptClass, value);
get => _scriptClassName;
set mut
{
if (_scriptClassName == null)
_scriptClassName = new String(value);
_scriptClassName.Set(value);
}
}
public ScriptInstance Instance
@@ -525,16 +531,13 @@ namespace GlitchyEngine.World
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 IsCreated => _instance?.IsCreated ?? false;
public void Dispose() mut
{
ReleaseRefAndNullify!(_scriptClass);
delete _scriptClassName;
ReleaseRefAndNullify!(_instance);
}
}
+2 -3
View File
@@ -93,11 +93,10 @@ namespace GlitchyEngine.World
Entity targetEntity = target.GetEntityByID(sourceEntity.UUID);
ScriptComponent* targetComponent = targetEntity.AddComponent<ScriptComponent>();
targetComponent.ScriptClass = sourceComponent.ScriptClass;
targetComponent.Instance = new ScriptInstance(sourceComponent.ScriptClass);
targetComponent.Instance..ReleaseRef();
targetComponent.ScriptClassName = sourceComponent.ScriptClassName;
// 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);
}
+26 -19
View File
@@ -189,9 +189,11 @@ class SceneSerializer
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);
@@ -201,11 +203,10 @@ class SceneSerializer
{
for (var (fieldName, fieldInstance) in fields)
{
if (fieldInstance.Field.FieldType == .None)
if (fieldInstance.Type == .None)
continue;
switch (fieldInstance.Field.FieldType)
switch (fieldInstance.Type)
{
case .Enum, .Class, .Struct:
// TODO: implement
@@ -213,10 +214,10 @@ class SceneSerializer
writer.Identifier(fieldName);
String str = scope .();
fieldInstance.Field.FieldType.ToString(str);
fieldInstance.Type.ToString(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 (ScriptEngine.EntityClasses.TryGetValue(scriptClassName, let scriptClass))
{
//if (ScriptEngine.EntityClasses.TryGetValue(scriptClassName, let scriptClass))
/*{
component.ScriptClass = scriptClass;
}
}*/
component.ScriptClassName = 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,
// 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());
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();
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);
dontRemoveComma = true;
continue;
@@ -622,9 +629,9 @@ class SceneSerializer
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);
dontRemoveComma = true;
continue;
@@ -632,9 +639,9 @@ class SceneSerializer
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);
dontRemoveComma = true;
continue;
@@ -642,7 +649,7 @@ class SceneSerializer
}
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}\"))");
}
}