Try catch in C# Glue Functions called by engine, removed test ThrowException method

This commit is contained in:
Simon Lübeß
2025-08-03 12:00:35 +02:00
parent 184b92e95c
commit cc38236184
2 changed files with 189 additions and 111 deletions
@@ -113,7 +113,6 @@ static class CoreClrHelper
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateScriptInstance", out _createScriptInstance); GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateScriptInstance", out _createScriptInstance);
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "ThrowException", out _throwException);
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "RegisterComponentType", out _registerComponentType); GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "RegisterComponentType", out _registerComponentType);
InitEntityFunctions(); InitEntityFunctions();
+188 -109
View File
@@ -74,9 +74,14 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void SetEngineFunctions(EngineFunctions* engineFunctions) public static void SetEngineFunctions(EngineFunctions* engineFunctions)
{ {
_engineFunctions = *engineFunctions; try
{
Log.Info("Yeah"); _engineFunctions = *engineFunctions;
}
catch (Exception e)
{
Log.Exception(e);
}
} }
/// <summary> /// <summary>
@@ -85,27 +90,27 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void LoadScriptAssembly(byte* assemblyData, long assemblyLength, byte* pdbData, long pdbLength) public static void LoadScriptAssembly(byte* assemblyData, long assemblyLength, byte* pdbData, long pdbLength)
{ {
using UnmanagedMemoryStream assemblyStream = new(assemblyData, assemblyLength); try
{
using UnmanagedMemoryStream assemblyStream = new(assemblyData, assemblyLength);
using UnmanagedMemoryStream? pdbStream = (pdbData != null) ? new UnmanagedMemoryStream(pdbData, pdbLength) : null; using UnmanagedMemoryStream? pdbStream = (pdbData != null) ? new UnmanagedMemoryStream(pdbData, pdbLength) : null;
LoadAssembly(assemblyStream, pdbStream); LoadAssembly(assemblyStream, pdbStream);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
private static void LoadAssembly(Stream assemblyStream, Stream? pdbStream) private static void LoadAssembly(Stream assemblyStream, Stream? pdbStream)
{ {
try _scriptAssemblyContext ??= new AssemblyLoadContext("ScriptContext", true);
{
_scriptAssemblyContext ??= new AssemblyLoadContext("ScriptContext", true);
_appAssembly = _scriptAssemblyContext.LoadFromStream(assemblyStream, pdbStream); _appAssembly = _scriptAssemblyContext.LoadFromStream(assemblyStream, pdbStream);
Debug.Assert(_appAssembly != null); Debug.Assert(_appAssembly != null);
}
catch (Exception e)
{
Console.WriteLine($"Fehler: {e}");
}
} }
/// <summary> /// <summary>
@@ -114,8 +119,15 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void UnloadAssemblies() public static void UnloadAssemblies()
{ {
_scriptAssemblyContext?.Unload(); try
_scriptAssemblyContext = null; {
_scriptAssemblyContext?.Unload();
_scriptAssemblyContext = null;
}
catch (Exception e)
{
Log.Exception(e);
}
} }
private static NativeScriptClassInfo[]? _unsafeClasses; private static NativeScriptClassInfo[]? _unsafeClasses;
@@ -148,61 +160,68 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void GetScriptClasses(NativeScriptClassInfo** outBuffer, long* length) public static void GetScriptClasses(NativeScriptClassInfo** outBuffer, long* length)
{ {
using var contextualReflection = AssemblyLoadContext.EnterContextualReflection(_appAssembly); try
Debug.Assert(_appAssembly != null);
Internal_FreeScriptClassNames();
var types = _appAssembly.GetTypes();
List<(string Name, Guid Guid, ScriptMethods AvailableMethods, bool runInEditMode)> scriptClasses = new();
foreach (var type in types)
{ {
if (type.IsSubclassOf(typeof(Entity))) using var contextualReflection = AssemblyLoadContext.EnterContextualReflection(_appAssembly);
Debug.Assert(_appAssembly != null);
Internal_FreeScriptClassNames();
var types = _appAssembly.GetTypes();
List<(string Name, Guid Guid, ScriptMethods AvailableMethods, bool runInEditMode)> scriptClasses = new();
foreach (var type in types)
{ {
string? name = type.FullName; if (type.IsSubclassOf(typeof(Entity)))
if (name == null)
continue;
Guid guid = type.GUID;
ScriptMethods methods = ScriptMethods.None;
static ScriptMethods HasMethod(Type type, string methodName, ScriptMethods methodFlag)
{ {
MethodInfo? methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); string? name = type.FullName;
return methodInfo != null ? methodFlag : ScriptMethods.None; if (name == null)
continue;
Guid guid = type.GUID;
ScriptMethods methods = ScriptMethods.None;
static ScriptMethods HasMethod(Type type, string methodName, ScriptMethods methodFlag)
{
MethodInfo? methodInfo = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
return methodInfo != null ? methodFlag : ScriptMethods.None;
}
methods |= HasMethod(type, nameof(Entity.OnCreate), ScriptMethods.OnCreate);
methods |= HasMethod(type, nameof(Entity.OnUpdate), ScriptMethods.OnUpdate);
methods |= HasMethod(type, nameof(Entity.OnDestroy), ScriptMethods.OnDestroy);
bool runInEditMode = type.HasCustomAttribute<RunInEditModeAttribute>();
scriptClasses.Add((name, guid, methods, runInEditMode));
} }
methods |= HasMethod(type, nameof(Entity.OnCreate), ScriptMethods.OnCreate);
methods |= HasMethod(type, nameof(Entity.OnUpdate), ScriptMethods.OnUpdate);
methods |= HasMethod(type, nameof(Entity.OnDestroy), ScriptMethods.OnDestroy);
bool runInEditMode = type.HasCustomAttribute<RunInEditModeAttribute>();
scriptClasses.Add((name, guid, methods, runInEditMode));
} }
}
_unsafeClasses = new NativeScriptClassInfo[scriptClasses.Count]; _unsafeClasses = new NativeScriptClassInfo[scriptClasses.Count];
for (int i = 0; i < _unsafeClasses.Length; i++) for (int i = 0; i < _unsafeClasses.Length; i++)
{
_unsafeClasses[i] = new NativeScriptClassInfo()
{ {
Guid = scriptClasses[i].Guid, _unsafeClasses[i] = new NativeScriptClassInfo()
Name = Marshal.StringToCoTaskMemUTF8(scriptClasses[i].Name), {
Methods = scriptClasses[i].AvailableMethods, Guid = scriptClasses[i].Guid,
RunInEditMode = scriptClasses[i].runInEditMode Name = Marshal.StringToCoTaskMemUTF8(scriptClasses[i].Name),
}; Methods = scriptClasses[i].AvailableMethods,
} RunInEditMode = scriptClasses[i].runInEditMode
};
}
*outBuffer = (NativeScriptClassInfo*)Marshal.UnsafeAddrOfPinnedArrayElement(_unsafeClasses, 0); *outBuffer = (NativeScriptClassInfo*)Marshal.UnsafeAddrOfPinnedArrayElement(_unsafeClasses, 0);
*length = _unsafeClasses.Length; *length = _unsafeClasses.Length;
}
catch (Exception e)
{
Log.Exception(e);
}
} }
/// <summary> /// <summary>
@@ -211,7 +230,14 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void FreeScriptClassNames() public static void FreeScriptClassNames()
{ {
Internal_FreeScriptClassNames(); try
{
Internal_FreeScriptClassNames();
}
catch (Exception e)
{
Log.Exception(e);
}
} }
private static void Internal_FreeScriptClassNames() private static void Internal_FreeScriptClassNames()
@@ -237,8 +263,7 @@ internal static unsafe partial class ScriptGlue
} }
catch (Exception e) catch (Exception e)
{ {
Console.WriteLine(e); Log.Exception(e);
// TODO: Log exceptions to console
} }
} }
@@ -305,15 +330,22 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void CreateScriptInstance(UUID entityId, byte* scriptClassName) public static void CreateScriptInstance(UUID entityId, byte* scriptClassName)
{ {
Type? scriptType = GetTypeFromNativeString(scriptClassName); try
{
Type? scriptType = GetTypeFromNativeString(scriptClassName);
Debug.Assert(scriptType != null, "Script class Type not found."); Debug.Assert(scriptType != null, "Script class Type not found.");
Entity? scriptInstance = ActivatorExtension.CreateEngineObject(scriptType, entityId) as Entity; Entity? scriptInstance = ActivatorExtension.CreateEngineObject(scriptType, entityId) as Entity;
Debug.Assert(scriptInstance != null, "Failed to create script instance."); Debug.Assert(scriptInstance != null, "Failed to create script instance.");
EntityScriptInstances.Add(entityId, (scriptInstance!, scriptType)); EntityScriptInstances.Add(entityId, (scriptInstance!, scriptType));
}
catch (Exception e)
{
Log.Exception(e);
}
} }
struct ComponentFunctionPointers struct ComponentFunctionPointers
@@ -331,33 +363,34 @@ internal static unsafe partial class ScriptGlue
delegate* unmanaged[Cdecl]<UUID, EngineResult> hasComponent, delegate* unmanaged[Cdecl]<UUID, EngineResult> hasComponent,
delegate* unmanaged[Cdecl]<UUID, void> removeComponent) delegate* unmanaged[Cdecl]<UUID, void> removeComponent)
{ {
string? beefComponentTypeName = Marshal.PtrToStringUTF8((IntPtr)fullComponentTypeName); try
if (beefComponentTypeName == null)
return;
foreach(Type componentType in TypeExtension.FindDerivedTypes(typeof(Component)))
{ {
if (!componentType.TryGetCustomAttribute(out EngineClassAttribute mapping) || string? beefComponentTypeName = Marshal.PtrToStringUTF8((IntPtr)fullComponentTypeName);
mapping.EngineClassName != beefComponentTypeName) continue;
ComponentTypeFunctions[componentType] = new ComponentFunctionPointers if (beefComponentTypeName == null)
return;
foreach(Type componentType in TypeExtension.FindDerivedTypes(typeof(Component)))
{ {
AddComponent = addComponent, if (!componentType.TryGetCustomAttribute(out EngineClassAttribute mapping) ||
HasComponent = hasComponent, mapping.EngineClassName != beefComponentTypeName) continue;
RemoveComponent = removeComponent
};
return; ComponentTypeFunctions[componentType] = new ComponentFunctionPointers
{
AddComponent = addComponent,
HasComponent = hasComponent,
RemoveComponent = removeComponent
};
return;
}
Log.Error($"Failed to register component type \"{beefComponentTypeName}\": No matching component class found.");
}
catch (Exception e)
{
Log.Exception(e);
} }
Log.Error($"Failed to register component type \"{beefComponentTypeName}\": No matching component class found.");
}
[UnmanagedCallersOnly]
internal static void ThrowException(IntPtr message)
{
throw new Exception(Marshal.PtrToStringUTF8(message));
} }
#region EntitySerializer #region EntitySerializer
@@ -365,49 +398,91 @@ internal static unsafe partial class ScriptGlue
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void CreateSerializationContext(IntPtr engineSerializer) public static void CreateSerializationContext(IntPtr engineSerializer)
{ {
EntitySerializer.CreateSerializationContext(engineSerializer); try
{
EntitySerializer.CreateSerializationContext(engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void DestroySerializationContext(IntPtr engineSerializer) public static void DestroySerializationContext(IntPtr engineSerializer)
{ {
EntitySerializer.DestroySerializationContext(engineSerializer); try
{
EntitySerializer.DestroySerializationContext(engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void EntitySerializer_Serialize(UUID entityId, IntPtr engineObject, IntPtr engineSerializer) public static void EntitySerializer_Serialize(UUID entityId, IntPtr engineObject, IntPtr engineSerializer)
{ {
if (!EntityScriptInstances.TryGetValue(entityId, out var match)) try
return; {
if (!EntityScriptInstances.TryGetValue(entityId, out var match))
return;
EntitySerializer.Serialize(match.Entity, engineObject, engineSerializer); EntitySerializer.Serialize(match.Entity, engineObject, engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void EntitySerializer_Deserialize(UUID entityId, IntPtr engineObject, IntPtr engineSerializer) public static void EntitySerializer_Deserialize(UUID entityId, IntPtr engineObject, IntPtr engineSerializer)
{ {
if (!EntityScriptInstances.TryGetValue(entityId, out var match)) try
return; {
if (!EntityScriptInstances.TryGetValue(entityId, out var match))
return;
EntitySerializer.Deserialize(match.Entity, engineObject, engineSerializer); EntitySerializer.Deserialize(match.Entity, engineObject, engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void EntitySerializer_SerializeStaticFields(byte* fullTypeName, IntPtr engineObject, IntPtr engineSerializer) public static void EntitySerializer_SerializeStaticFields(byte* fullTypeName, IntPtr engineObject, IntPtr engineSerializer)
{ {
Type? type = GetTypeFromNativeString(fullTypeName); try
Debug.Assert(type != null); {
Type? type = GetTypeFromNativeString(fullTypeName);
Debug.Assert(type != null);
EntitySerializer.SerializeStaticFields(type, engineObject, engineSerializer); EntitySerializer.SerializeStaticFields(type, engineObject, engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
[UnmanagedCallersOnly] [UnmanagedCallersOnly]
public static void EntitySerializer_DeserializeStaticFields(byte* fullTypeName, IntPtr engineObject, IntPtr engineSerializer) public static void EntitySerializer_DeserializeStaticFields(byte* fullTypeName, IntPtr engineObject, IntPtr engineSerializer)
{ {
Type? type = GetTypeFromNativeString(fullTypeName); try
Debug.Assert(type != null); {
Type? type = GetTypeFromNativeString(fullTypeName);
Debug.Assert(type != null);
EntitySerializer.DeserializeStaticFields(type, engineObject, engineSerializer); EntitySerializer.DeserializeStaticFields(type, engineObject, engineSerializer);
}
catch (Exception e)
{
Log.Exception(e);
}
} }
#endregion EntitySerializer #endregion EntitySerializer
@@ -454,8 +529,12 @@ internal static unsafe partial class ScriptGlue
switch (type) switch (type)
{ {
case SerializationType.String: case SerializationType.String:
valueObjectConverted = (void*)Marshal.StringToCoTaskMemUTF8(fullTypeName); case SerializationType.Enum:
deleteValueObject = true; if (valueObject is String stringValue)
{
valueObjectConverted = (void*)Marshal.StringToCoTaskMemUTF8(stringValue);
deleteValueObject = true;
}
break; break;
default: default:
if (valueObject is not null) if (valueObject is not null)