StudioCherno/Coral

Unable to unload and reload assembly when loading more than one

antopilo opened this issue · 2 comments

It used to not be possible to unload/load an assembly since the reflection improvements.

It works fine when you load 1 assembly and unload it. But doesnt seem to work properly when you load more than 1 assembly and unload them and reload them.

You get the same exception as before:

Unhandled native exception: System.Reflection.TargetException: Object does not match target type.
   at System.Reflection.MethodBase.ValidateInvokeTarget(Object target)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Coral.Managed.ManagedObject.InvokeMethod(IntPtr InObjectHandle, NativeString InMethodName, IntPtr InParameters, ManagedType* InParameterTypes, Int32 InParameterCount)

This is how I am loading my assemblies:

_LoadContext = m_HostInstance->CreateAssemblyLoadContext(m_ContextName);

// Load Nuake assembly DLL
const std::string absoluteAssemblyPath = FileSystem::Root + m_NetDirectory + "/" + m_EngineAssemblyName;
m_NuakeAssembly = m_LoadContext.LoadAssembly(absoluteAssemblyPath);

// Upload internal calls for each module
// --------------------------------------------------
for (const auto& netModule : m_Modules)
{
	const std::string inClassName = m_Scope + '.' + netModule->GetModuleName();
	for (const auto& [methodName, methodPtr] : netModule->GetMethods())
	{
		m_NuakeAssembly.AddInternalCall(inClassName, methodName, methodPtr);
	}
}

m_NuakeAssembly.UploadInternalCalls();
		
m_GameAssembly = m_LoadContext.LoadAssembly(absoluteGameAssemblyPath);
// Detecting entity scripts
for (auto& type : m_GameAssembly.GetTypes())
{
	Logger::Log(std::string("Detected type: ") + std::string(type->GetName()), ".net");
	Logger::Log(std::string("Detected base type: ") + std::string(type->GetBaseType().GetName()), ".net");
                
	const std::string baseTypeName = std::string(type->GetBaseType().GetName());
	if (baseTypeName == "Entity")
	 {
		// We have found an entity script.
		m_GameEntityTypes[std::string(type->GetName())] = type;
	 }
}

This is how I am unloading:

for (auto& [entity, managedObject] : m_EntityToManagedObjects)
{
	managedObject.Destroy();
}

m_GameEntityTypes.clear();
Coral::GC::Collect();

m_HostInstance->UnloadAssemblyLoadContext(m_LoadContext);

m_EntityToManagedObjects.clear();

@antopilo I can't reproduce this after 0041cda, could you verify that this has been fixed after this commit?

Seems to have been fixed after 0041cda ! 🥳