mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-11-04 12:51:48 +00:00
Properly unload script assembly when reloading
This commit is contained in:
@@ -29,7 +29,9 @@ static class CoreClrHelper
|
||||
|
||||
//static function void(char8* path) LoadScriptAssembly;
|
||||
static LoadScriptAssemblyFunc _loadScriptAssembly;
|
||||
static function void() _unloadAssemblies;
|
||||
static function void() _unloadScriptAssembly;
|
||||
|
||||
static function void() _waitUntilOldAssemblyDead;
|
||||
|
||||
// public static unsafe void GetScriptClasses(void** outBuffer, long* length)
|
||||
private function void GetScriptClassesFunc(void** outBuffer, int64* length);
|
||||
@@ -108,8 +110,10 @@ static class CoreClrHelper
|
||||
{
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "LoadScriptAssembly", out _loadScriptAssembly);
|
||||
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "UnloadAssemblies", out _unloadAssemblies);
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "UnloadScriptAssembly", out _unloadScriptAssembly);
|
||||
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "WaitUntilOldAssemblyDead", out _waitUntilOldAssemblyDead);
|
||||
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "GetScriptClasses", out _getScriptClasses);
|
||||
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "FreeScriptClassNames", out _freeScriptClassNames);
|
||||
@@ -130,16 +134,21 @@ static class CoreClrHelper
|
||||
GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "InvokeEntityOnCollisionEnter2D", out _entityScriptFunctions.OnCollisionEnter2D);
|
||||
}
|
||||
|
||||
public static void LoadAppAssembly(Span<uint8> appAssemblyData, Span<uint8> pdbData)
|
||||
public static void LoadScriptAssembly(Span<uint8> appAssemblyData, Span<uint8> pdbData)
|
||||
{
|
||||
_loadScriptAssembly(appAssemblyData.Ptr, appAssemblyData.Length, pdbData.Ptr, pdbData.Length);
|
||||
}
|
||||
|
||||
public static void UnloadAssemblies()
|
||||
public static void UnloadScriptAssembly()
|
||||
{
|
||||
_unloadAssemblies();
|
||||
_unloadScriptAssembly();
|
||||
}
|
||||
|
||||
public static void WaitUntilOldAssemblyDead()
|
||||
{
|
||||
_waitUntilOldAssemblyDead();
|
||||
}
|
||||
|
||||
/// Gets an array of script class infos. Use FreeScriptClassNames to release the buffer.
|
||||
public static void GetScriptClasses(out void* outBuffer, out int64 entryCount)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@ class EntitySerializerWrapper : NewScriptClass
|
||||
function void DeserializeMethod(UUID entityId, void* serializedObjPtr, void* serializerPtr);
|
||||
function void SerializeStaticMethod(char8* fullTypeName, void* serializedObjPtr, void* serializerPtr);
|
||||
function void DeserializeStaticMethod(char8* fullTypeName, void* serializedObjPtr, void* serializerPtr);
|
||||
function void FinishSerializationMethod(void* serializerPtr);
|
||||
|
||||
private CreateSerializationContextMethod _createSerializationContextMethod;
|
||||
//private ClearSerializationContextMethod _clearSerializationContextMethod;
|
||||
@@ -25,16 +26,19 @@ class EntitySerializerWrapper : NewScriptClass
|
||||
private DeserializeMethod _deserializeMethod;
|
||||
private SerializeStaticMethod _serializeStaticMethod;
|
||||
private DeserializeStaticMethod _deserializeStaticMethod;
|
||||
private FinishSerializationMethod _finishSerializationMethod;
|
||||
|
||||
[AllowAppend]
|
||||
public this() : base("GlitchyEngine.Serialization.EntitySerializer", .Empty, .None, false)
|
||||
{
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "CreateSerializationContext", out _createSerializationContextMethod);
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "DestroySerializationContext", out _destroySerializationContextMethod);
|
||||
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "EntitySerializer_Serialize", out _serializeMethod);
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "EntitySerializer_Deserialize", out _deserializeMethod);
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "EntitySerializer_SerializeStaticFields", out _serializeStaticMethod);
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "EntitySerializer_DeserializeStaticFields", out _deserializeStaticMethod);
|
||||
CoreClrHelper.GetFunctionPointerUnmanagedCallersOnly("GlitchyEngine.ScriptGlue, ScriptCore", "EntitySerializer_FinishSerialization", out _finishSerializationMethod);
|
||||
}
|
||||
|
||||
public void CreateSerializationContext(ScriptInstanceSerializer serializer)
|
||||
@@ -93,4 +97,10 @@ class EntitySerializerWrapper : NewScriptClass
|
||||
|
||||
_deserializeStaticMethod(@class.FullName.CStr(), serializedObjectPtr, serializerPtr);
|
||||
}
|
||||
|
||||
public void FinishSerialization(ScriptInstanceSerializer serializer)
|
||||
{
|
||||
void* serializerPtr = Internal.UnsafeCastToPtr(serializer);
|
||||
_finishSerializationMethod(serializerPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,32 +209,6 @@ static class ScriptEngine
|
||||
CoreClrHelper.Init(ScriptCorePath);
|
||||
}
|
||||
|
||||
/*static void InitMono()
|
||||
{
|
||||
Mono.mono_set_assemblies_path("mono/lib/4.5");
|
||||
|
||||
if (_debuggingEnabled)
|
||||
{
|
||||
char8*[2] options = .(
|
||||
"--debugger-agent=transport=dt_socket,address=127.0.0.1:2550,server=y,suspend=n,loglevel=3,logfile=MonoDebugger.log",
|
||||
"--soft-breakpoints"
|
||||
);
|
||||
|
||||
Mono.mono_jit_parse_options(options.Count, &options);
|
||||
Mono.mono_debug_init(.Mono);
|
||||
}
|
||||
|
||||
s_RootDomain = Mono.mono_jit_init("GlitchyEngineJITRuntime");
|
||||
Log.EngineLogger.Assert(s_RootDomain != null, "Failed to initialize mono root domain");
|
||||
|
||||
if (_debuggingEnabled)
|
||||
{
|
||||
Mono.mono_debug_domain_create(s_RootDomain);
|
||||
}
|
||||
|
||||
Mono.mono_thread_set_main(Mono.mono_thread_current());
|
||||
}*/
|
||||
|
||||
static bool _requestingReload = false;
|
||||
|
||||
static void InitAssemblyWatcher()
|
||||
@@ -301,7 +275,7 @@ static class ScriptEngine
|
||||
|
||||
File.ReadAll(pdbPath, pdbData);
|
||||
|
||||
CoreClrHelper.LoadAppAssembly(data, pdbData);
|
||||
CoreClrHelper.LoadScriptAssembly(data, pdbData);
|
||||
|
||||
GetEntitiesFromAssemblies();
|
||||
|
||||
@@ -445,14 +419,15 @@ static class ScriptEngine
|
||||
{
|
||||
Debug.Profiler.ProfileFunction!();
|
||||
|
||||
Log.EngineLogger.Info("Reloading script assemblies.");
|
||||
// TODO: Assembly reload might actually take a second. We should consider doing it in a separate thread in the editor.
|
||||
|
||||
Log.EngineLogger.Info("Reloading script assemblies.");
|
||||
|
||||
ScriptInstanceSerializer contextSerializer = scope .();
|
||||
|
||||
contextSerializer.SerializeScriptInstances();
|
||||
|
||||
// TODO: Unload script assemblies, remove class handles, fire unload events?
|
||||
UnloadScriptAssemblies();
|
||||
|
||||
LoadScriptAssemblies();
|
||||
|
||||
@@ -479,15 +454,28 @@ static class ScriptEngine
|
||||
Log.EngineLogger.Info("Script assemblies reloaded!");
|
||||
}
|
||||
|
||||
private static void UnloadScriptAssemblies()
|
||||
{
|
||||
for (let (id, scriptInstance) in _entityScriptInstances)
|
||||
{
|
||||
if (Context.GetEntityByID(id) case .Ok(let entity))
|
||||
{
|
||||
ScriptComponent* script = entity.GetComponent<ScriptComponent>();
|
||||
DestroyInstance(entity, script);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(false, "Entity script instance exists but no entity?!");
|
||||
}
|
||||
}
|
||||
|
||||
CoreClrHelper.UnloadScriptAssembly();
|
||||
CoreClrHelper.WaitUntilOldAssemblyDead();
|
||||
}
|
||||
|
||||
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);
|
||||
s_RootDomain = null;*/
|
||||
UnloadScriptAssemblies();
|
||||
}
|
||||
|
||||
/// Returns the script class with the given name, or null, if no such class exists.
|
||||
|
||||
@@ -31,6 +31,15 @@ public class ScriptInstanceSerializer
|
||||
ScriptEngine.Classes.EntitySerializer.CreateSerializationContext(this);
|
||||
}
|
||||
|
||||
/// Signals, that no more objects will be serialized into this context.
|
||||
/// This allows the managed serialization context to do cleanup:
|
||||
/// i. e. for C# we can release references to types which allows us to cleanup the old script assembly.
|
||||
public void FinishSerialization()
|
||||
{
|
||||
ScriptEngine.Classes.EntitySerializer.FinishSerialization(this);
|
||||
}
|
||||
|
||||
|
||||
/// Serializes all script instances that are currently managed by the ScriptEngine.
|
||||
public void SerializeScriptInstances()
|
||||
{
|
||||
@@ -47,6 +56,8 @@ public class ScriptInstanceSerializer
|
||||
{
|
||||
SerializeStaticScriptClassFields(scriptClass);
|
||||
}
|
||||
|
||||
FinishSerialization();
|
||||
}
|
||||
|
||||
/// Serializes the given script instance.
|
||||
@@ -79,6 +90,8 @@ public class ScriptInstanceSerializer
|
||||
{
|
||||
DeserializeStaticScriptClassFields(scriptClass);
|
||||
}
|
||||
|
||||
FinishSerialization();
|
||||
}
|
||||
|
||||
/// Deserializes the data into the given script instance, if there is data available.
|
||||
|
||||
Reference in New Issue
Block a user