mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Save and Load script data from files
This commit is contained in:
@@ -51,6 +51,17 @@ public class Entity : EngineObject
|
||||
Create(name, components);
|
||||
}
|
||||
|
||||
protected void PrintDecimal(decimal value)
|
||||
{
|
||||
ScriptGlue.Print_Decimal(value);
|
||||
}
|
||||
|
||||
protected decimal GetDecimal(string value)
|
||||
{
|
||||
ScriptGlue.Get_Decimal(value, out var dec);
|
||||
return dec;
|
||||
}
|
||||
|
||||
private void Create(string name, Type[] components)
|
||||
{
|
||||
ScriptGlue.Entity_Create(this, name, components, out _uuid);
|
||||
|
||||
@@ -121,6 +121,12 @@ internal static class ScriptGlue
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern float4 modf_float4(float4 x, out float4 integerPart);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Print_Decimal(decimal value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
internal static extern void Get_Decimal(string str, out decimal value);
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -152,7 +158,7 @@ internal static class ScriptGlue
|
||||
internal static extern void Serialization_CreateObject(IntPtr currentContext, string fullTypeName, out IntPtr context, out UUID id);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern unsafe void Serialization_DeserializeField(IntPtr internalContext, SerializationType expectedType, string fieldName, byte* value);
|
||||
public static extern unsafe void Serialization_DeserializeField(IntPtr internalContext, SerializationType expectedType, string fieldName, byte* value, out SerializationType actualType);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
public static extern void Serialization_GetObject(IntPtr internalContext, UUID id, out IntPtr objectContext);
|
||||
|
||||
@@ -38,7 +38,7 @@ public class DeserializationObject
|
||||
|
||||
private object _instance;
|
||||
|
||||
private Dictionary<string, Type> _fullNameToType = new();
|
||||
private Dictionary<string, Type?> _fullNameToType = new();
|
||||
|
||||
private delegate object? DeserializeMethod(DeserializationObject container, string fieldName, Type fieldType);
|
||||
|
||||
@@ -47,7 +47,7 @@ public class DeserializationObject
|
||||
/// <summary>
|
||||
/// Gets the type that was originally stored in the container, or null, if the type doesn't exist.
|
||||
/// </summary>
|
||||
public Type StoredType
|
||||
public Type? StoredType
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -88,7 +88,7 @@ public class DeserializationObject
|
||||
}
|
||||
}
|
||||
|
||||
public Type FindType(string fullName)
|
||||
public Type? FindType(string fullName)
|
||||
{
|
||||
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies().Reverse())
|
||||
{
|
||||
@@ -101,19 +101,19 @@ public class DeserializationObject
|
||||
return null;
|
||||
}
|
||||
|
||||
public Type GetTypeFromName(string fullName)
|
||||
public Type? GetTypeFromName(string fullName)
|
||||
{
|
||||
if (_fullNameToType.TryGetValue(fullName, out Type storedType))
|
||||
if (_fullNameToType.TryGetValue(fullName, out Type? storedType))
|
||||
return storedType;
|
||||
|
||||
Type type = FindType(fullName);
|
||||
|
||||
Type? type = FindType(fullName);
|
||||
|
||||
_fullNameToType.Add(fullName, type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
public DeserializationObject GetDeserializedObject(UUID id)
|
||||
public DeserializationObject? GetDeserializedObject(UUID id)
|
||||
{
|
||||
DeserializationObject context;
|
||||
|
||||
@@ -121,7 +121,12 @@ public class DeserializationObject
|
||||
return context;
|
||||
|
||||
ScriptGlue.Serialization_GetObject(_internalContext, id, out IntPtr contextPtr);
|
||||
|
||||
|
||||
if (contextPtr == IntPtr.Zero)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
context = new DeserializationObject(contextPtr, id, DeserializedClasses);
|
||||
|
||||
DeserializedClasses.Add(id, context);
|
||||
@@ -155,27 +160,42 @@ public class DeserializationObject
|
||||
|
||||
[FieldOffset(0)]
|
||||
public EngineObjectReferenceHelper EngineObjectReference;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public ulong UInt;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public long Int;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public UUID UUID;
|
||||
}
|
||||
|
||||
public T GetFieldValue<T>(string fieldName, SerializationType serializationType)
|
||||
public T? GetFieldValue<T>(string fieldName, SerializationType expectedType)
|
||||
{
|
||||
return (T)GetFieldValue(fieldName, serializationType);
|
||||
return (T?)GetFieldValue(fieldName, expectedType);
|
||||
}
|
||||
|
||||
public unsafe object GetFieldValue(string fieldName, SerializationType serializationType)
|
||||
public unsafe object? GetFieldValue(string fieldName, SerializationType expectedType)
|
||||
{
|
||||
string completeFieldName = $"{_structScopeName}{fieldName}";
|
||||
|
||||
// Decimal is the larges primitive we store so we use a decimal as stack allocated memory (because stackalloc doesn't seem to work :(
|
||||
//decimal backingFieldOnStack = 0.0m;
|
||||
byte* rawData = stackalloc byte[sizeof(DataHelper)];
|
||||
//byte* rawData = (byte*)&backingFieldOnStack;
|
||||
|
||||
//byte* rawData = stackalloc byte[sizeof(DataHelper)];
|
||||
//ref DataHelper dataHelper = ref Unsafe.AsRef<DataHelper>(rawData);
|
||||
|
||||
ref DataHelper dataHelper = ref Unsafe.AsRef<DataHelper>(rawData);
|
||||
DataHelper dataHelper = new();
|
||||
byte* rawData = (byte*)Unsafe.AsPointer(ref dataHelper);
|
||||
|
||||
ScriptGlue.Serialization_DeserializeField(_internalContext, serializationType, completeFieldName, rawData);
|
||||
// //byte* rawData = stackalloc byte[sizeof(DataHelper)];
|
||||
// //ref DataHelper dataHelper = ref Unsafe.AsRef<DataHelper>(rawData);
|
||||
|
||||
string GetString()
|
||||
ScriptGlue.Serialization_DeserializeField(_internalContext, expectedType, completeFieldName, rawData, out SerializationType actualType);
|
||||
|
||||
string? GetString()
|
||||
{
|
||||
// rawData contains a Pointer and a string length!
|
||||
byte* utf8Ptr = *(byte**)rawData;
|
||||
@@ -191,48 +211,50 @@ public class DeserializationObject
|
||||
return Encoding.UTF8.GetString(utf8Ptr, (int)length);
|
||||
}
|
||||
|
||||
switch (serializationType)
|
||||
object? value = actualType switch
|
||||
{
|
||||
case SerializationType.Bool:
|
||||
return *(bool*)rawData;
|
||||
case SerializationType.Char:
|
||||
return *(char*)rawData;
|
||||
case SerializationType.String:
|
||||
return GetString();
|
||||
case SerializationType.Int8:
|
||||
return *(sbyte*)rawData;
|
||||
case SerializationType.Int16:
|
||||
return *(short*)rawData;
|
||||
case SerializationType.Int32:
|
||||
return *(int*)rawData;
|
||||
case SerializationType.Int64:
|
||||
return *(long*)rawData;
|
||||
case SerializationType.UInt8:
|
||||
return *(byte*)rawData;
|
||||
case SerializationType.UInt16:
|
||||
return *(ushort*)rawData;
|
||||
case SerializationType.UInt32:
|
||||
return *(uint*)rawData;
|
||||
case SerializationType.UInt64:
|
||||
return *(ulong*)rawData;
|
||||
SerializationType.Bool => *(bool*)rawData,
|
||||
SerializationType.Char => *(char*)rawData,
|
||||
SerializationType.String => GetString(),
|
||||
SerializationType.Int8 => *(sbyte*)rawData,
|
||||
SerializationType.Int16 => *(short*)rawData,
|
||||
SerializationType.Int32 => *(int*)rawData,
|
||||
SerializationType.Int64 => *(long*)rawData,
|
||||
SerializationType.UInt8 => *(byte*)rawData,
|
||||
SerializationType.UInt16 => *(ushort*)rawData,
|
||||
SerializationType.UInt32 => *(uint*)rawData,
|
||||
SerializationType.UInt64 => *(ulong*)rawData,
|
||||
SerializationType.Float => *(float*)rawData,
|
||||
SerializationType.Double => *(double*)rawData,
|
||||
SerializationType.Decimal => *(decimal*)rawData,
|
||||
SerializationType.Enum => GetString(),
|
||||
SerializationType.EntityReference => dataHelper.EngineObjectReference,
|
||||
SerializationType.ComponentReference => dataHelper.EngineObjectReference,
|
||||
SerializationType.ObjectReference => dataHelper.UUID,
|
||||
_ => NoValueDeserialized
|
||||
};
|
||||
|
||||
case SerializationType.Float:
|
||||
return *(float*)rawData;
|
||||
case SerializationType.Double:
|
||||
return *(double*)rawData;
|
||||
case SerializationType.Decimal:
|
||||
return *(decimal*)rawData;
|
||||
|
||||
case SerializationType.Enum:
|
||||
return GetString();
|
||||
case SerializationType.EntityReference:
|
||||
case SerializationType.ComponentReference:
|
||||
return dataHelper.EngineObjectReference;
|
||||
case SerializationType.ObjectReference:
|
||||
return *(UUID*)rawData;
|
||||
default:
|
||||
if (actualType != expectedType)
|
||||
{
|
||||
if (!actualType.CanConvertTo(expectedType))
|
||||
{
|
||||
return NoValueDeserialized;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Type? targetType = expectedType.GetTypeInstance();
|
||||
|
||||
return targetType != null ? Convert.ChangeType(value, targetType) : NoValueDeserialized;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"Failed to convert type {actualType} to {expectedType}: {e}");
|
||||
return NoValueDeserialized;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public void Deserialize(Entity entity)
|
||||
@@ -284,7 +306,8 @@ public class DeserializationObject
|
||||
if (fieldType.IsGenericType && _customDeserializers.TryGetValue(fieldType.GetGenericTypeDefinition(), out deserializeMethod))
|
||||
{
|
||||
deserializedValue = deserializeMethod(this, fieldName, fieldType);
|
||||
} return true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -407,9 +430,12 @@ public class DeserializationObject
|
||||
return null;
|
||||
|
||||
// Get serialization container for the instance
|
||||
DeserializationObject deserializedObject = GetDeserializedObject(id);
|
||||
DeserializationObject? deserializedObject = GetDeserializedObject(id);
|
||||
|
||||
Type type = deserializedObject.StoredType;
|
||||
if (deserializedObject == null)
|
||||
return NoValueDeserialized;
|
||||
|
||||
Type? type = deserializedObject.StoredType;
|
||||
|
||||
if (type == null || !type.IsAssignableTo(fieldType))
|
||||
return null;
|
||||
|
||||
@@ -7,34 +7,79 @@ using GlitchyEngine.Extensions;
|
||||
|
||||
namespace GlitchyEngine.Serialization;
|
||||
|
||||
public enum SerializationType : int
|
||||
[Flags]
|
||||
public enum SerializationType : uint
|
||||
{
|
||||
None,
|
||||
None = 0,
|
||||
|
||||
Bool,
|
||||
Bool = 1u << 31,
|
||||
|
||||
Char,
|
||||
String,
|
||||
TextTypes = 1 << 30,
|
||||
|
||||
Int8,
|
||||
Int16,
|
||||
Int32,
|
||||
Int64,
|
||||
UInt8,
|
||||
UInt16,
|
||||
UInt32,
|
||||
UInt64,
|
||||
Char = TextTypes | 1,
|
||||
String = TextTypes | 2,
|
||||
|
||||
Float,
|
||||
Double,
|
||||
Decimal,
|
||||
Number = 1 << 29,
|
||||
Integer = Number | 1 << 28,
|
||||
|
||||
Enum,
|
||||
Int8 = Integer | 1,
|
||||
Int16 = Integer | 2,
|
||||
Int32 = Integer | 3,
|
||||
Int64 = Integer | 4,
|
||||
UInt8 = Integer | 5,
|
||||
UInt16 = Integer | 6,
|
||||
UInt32 = Integer | 7,
|
||||
UInt64 = Integer | 8,
|
||||
|
||||
EntityReference,
|
||||
ComponentReference,
|
||||
FloatingPoint = Number | 1 << 27,
|
||||
|
||||
ObjectReference
|
||||
Float = FloatingPoint | 1,
|
||||
Double = FloatingPoint | 2,
|
||||
Decimal = FloatingPoint | 3,
|
||||
|
||||
Enum = 1 << 26,
|
||||
|
||||
EntityReference = 1 << 25,
|
||||
ComponentReference = 1 << 24,
|
||||
|
||||
ObjectReference = 1 << 23,
|
||||
}
|
||||
|
||||
public static class SerializationTypeExtension
|
||||
{
|
||||
public static bool CanConvertTo(this SerializationType currentType, SerializationType targetType)
|
||||
{
|
||||
if (currentType.HasFlag(SerializationType.Number) && targetType.HasFlag(SerializationType.Number))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Type? GetTypeInstance(this SerializationType currentType)
|
||||
{
|
||||
return currentType switch
|
||||
{
|
||||
SerializationType.Bool => typeof(bool),
|
||||
SerializationType.Char => typeof(char),
|
||||
SerializationType.String => typeof(string),
|
||||
SerializationType.Int8 => typeof(sbyte),
|
||||
SerializationType.Int16 => typeof(short),
|
||||
SerializationType.Int32 => typeof(int),
|
||||
SerializationType.Int64 => typeof(long),
|
||||
SerializationType.UInt8 => typeof(byte),
|
||||
SerializationType.UInt16 => typeof(ushort),
|
||||
SerializationType.UInt32 => typeof(uint),
|
||||
SerializationType.UInt64 => typeof(ulong),
|
||||
SerializationType.Float => typeof(float),
|
||||
SerializationType.Double => typeof(double),
|
||||
SerializationType.Decimal => typeof(decimal),
|
||||
SerializationType.Enum => typeof(Enum),
|
||||
SerializationType.EntityReference => typeof(UUID),
|
||||
SerializationType.ComponentReference => typeof(UUID),
|
||||
SerializationType.ObjectReference => typeof(UUID),
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
internal static class EntitySerializer
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SerializedObject
|
||||
if (_serializedClasses.TryGetValue(o, out context))
|
||||
return (context, false);
|
||||
|
||||
ScriptGlue.Serialization_CreateObject(_internalContext, o.GetType().FullName, out IntPtr contextPtr, out UUID id);
|
||||
ScriptGlue.Serialization_CreateObject(_internalContext, o.GetType().ToString(), out IntPtr contextPtr, out UUID id);
|
||||
|
||||
context = new SerializedObject(contextPtr, id, _serializedClasses);
|
||||
|
||||
@@ -102,7 +102,7 @@ public class SerializedObject
|
||||
{
|
||||
Type type = obj.GetType();
|
||||
|
||||
foreach (FieldInfo field in type.GetFields())
|
||||
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
|
||||
{
|
||||
if (!EntitySerializer.SerializeField(field))
|
||||
continue;
|
||||
@@ -144,7 +144,7 @@ public class SerializedObject
|
||||
|
||||
public void SerializeField(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
if (fieldType.IsPrimitive)
|
||||
if (fieldType.IsPrimitive || fieldType == typeof(decimal))
|
||||
{
|
||||
SerializePrimitive(fieldName, fieldValue, fieldType);
|
||||
}
|
||||
@@ -238,8 +238,6 @@ public class SerializedObject
|
||||
|
||||
public void SerializePrimitive(string fieldName, object fieldValue, Type fieldType)
|
||||
{
|
||||
Debug.Assert(fieldType.IsPrimitive, $"{fieldType} is not a primitive type.");
|
||||
|
||||
SerializationType type = SerializationType.None;
|
||||
|
||||
if (fieldType == typeof(bool))
|
||||
|
||||
Reference in New Issue
Block a user