Files
BusyRabbit/Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.cpp
wyatt 648386cd73 Lua向C#逻辑迁移 一期 #13
将整个插件代码上传
2025-10-26 21:48:39 +08:00

679 lines
21 KiB
C++

#include "CSManager.h"
#include "CSManagedGCHandle.h"
#include "CSAssembly.h"
#include "UnrealSharpCore.h"
#include "TypeGenerator/CSClass.h"
#include "Misc/Paths.h"
#include "Misc/App.h"
#include "UObject/Object.h"
#include "Misc/MessageDialog.h"
#include "Engine/Blueprint.h"
#include "UnrealSharpProcHelper/CSProcHelper.h"
#include <vector>
#include "CSBindsManager.h"
#include "CSNamespace.h"
#include "CSUnrealSharpSettings.h"
#include "Engine/UserDefinedEnum.h"
#include "Logging/StructuredLog.h"
#include "StructUtils/UserDefinedStruct.h"
#include "TypeGenerator/CSInterface.h"
#include "TypeGenerator/Factories/CSPropertyFactory.h"
#include "TypeGenerator/Register/CSBuilderManager.h"
#include "TypeGenerator/Register/TypeInfo/CSClassInfo.h"
#include "Utils/CSClassUtilities.h"
#ifdef _WIN32
#define PLATFORM_STRING(string) string
#elif defined(__unix__)
#define PLATFORM_STRING(string) TCHAR_TO_ANSI(string)
#elif defined(__APPLE__)
#define PLATFORM_STRING(string) TCHAR_TO_ANSI(string)
#endif
#ifdef __clang__
#pragma clang diagnostic ignored "-Wdangling-assignment"
#endif
UCSManager* UCSManager::Instance = nullptr;
UPackage* UCSManager::FindOrAddManagedPackage(const FCSNamespace Namespace)
{
if (UPackage* NativePackage = Namespace.TryGetAsNativePackage())
{
return NativePackage;
}
FCSNamespace CurrentNamespace = Namespace;
TArray<FCSNamespace> ParentNamespaces;
while (true)
{
ParentNamespaces.Add(CurrentNamespace);
if (!CurrentNamespace.GetParentNamespace(CurrentNamespace))
{
break;
}
}
UPackage* ParentPackage = nullptr;
for (int32 i = ParentNamespaces.Num() - 1; i >= 0; i--)
{
FCSNamespace ParentNamespace = ParentNamespaces[i];
FName PackageName = ParentNamespace.GetPackageName();
for (UPackage* Package : AllPackages)
{
if (PackageName == Package->GetFName())
{
ParentPackage = Package;
break;
}
}
if (!ParentPackage)
{
ParentPackage = NewObject<UPackage>(nullptr, PackageName, RF_Public);
ParentPackage->SetPackageFlags(PKG_CompiledIn);
AllPackages.Add(ParentPackage);
}
}
return ParentPackage;
}
void UCSManager::ForEachManagedField(const TFunction<void(UObject*)>& Callback) const
{
for (UPackage* Package : AllPackages)
{
ForEachObjectWithPackage(Package, [&Callback](UObject* Object)
{
Callback(Object);
return true;
}, false);
}
}
UPackage* UCSManager::GetPackage(const FCSNamespace Namespace)
{
UPackage* FoundPackage;
if (GetDefault<UCSUnrealSharpSettings>()->HasNamespaceSupport())
{
FoundPackage = FindOrAddManagedPackage(Namespace);
}
else
{
FoundPackage = GetGlobalManagedPackage();
}
return FoundPackage;
}
bool UCSManager::IsLoadingAnyAssembly() const
{
for (const TPair<FName, TObjectPtr<UCSAssembly>>& LoadedAssembly : LoadedAssemblies)
{
UCSAssembly* AssemblyPtr = LoadedAssembly.Value;
if (IsValid(AssemblyPtr) && AssemblyPtr->IsLoading())
{
return true;
}
}
return false;
}
void UCSManager::AddDynamicSubsystemClass(TSubclassOf<UDynamicSubsystem> SubsystemClass)
{
if (!IsValid(SubsystemClass))
{
UE_LOG(LogUnrealSharp, Warning, TEXT("Tried to add an invalid dynamic subsystem class"));
return;
}
if (!PendingDynamicSubsystemClasses.Contains(SubsystemClass))
{
PendingDynamicSubsystemClasses.Add(SubsystemClass);
}
TryInitializeDynamicSubsystems();
}
void UCSManager::Initialize()
{
#if WITH_EDITOR
FString DotNetInstallationPath = FCSProcHelper::GetDotNetDirectory();
if (DotNetInstallationPath.IsEmpty())
{
FString DialogText = FString::Printf(TEXT("UnrealSharp can't be initialized. An installation of .NET %s SDK can't be found on your system."), TEXT(DOTNET_MAJOR_VERSION));
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(DialogText));
return;
}
FString UnrealSharpLibraryPath = FCSProcHelper::GetUnrealSharpPluginsPath();
if (!FPaths::FileExists(UnrealSharpLibraryPath))
{
FString FullPath = FPaths::ConvertRelativePathToFull(UnrealSharpLibraryPath);
FString DialogText = FString::Printf(TEXT(
"The bindings library could not be found at the following location:\n%s\n\n"
"Most likely, the bindings library failed to build due to invalid generated glue."
), *FullPath);
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(DialogText));
return;
}
TArray<FString> ProjectPaths;
FCSProcHelper::GetAllProjectPaths(ProjectPaths);
// Compile the C# project for any changes done outside the editor.
if (!ProjectPaths.IsEmpty() && !FApp::IsUnattended() && !FCSProcHelper::InvokeUnrealSharpBuildTool(BUILD_ACTION_BUILD_WEAVE))
{
Initialize();
return;
}
// Remove this listener when the engine is shutting down.
// Otherwise, we'll get a crash when the GC cleans up all the UObject.
FCoreDelegates::OnPreExit.AddUObject(this, &UCSManager::OnEnginePreExit);
#endif
TypeBuilderManager = NewObject<UCSTypeBuilderManager>(this);
TypeBuilderManager->Initialize();
GUObjectArray.AddUObjectDeleteListener(this);
// Initialize the C# runtime.
if (!InitializeDotNetRuntime())
{
return;
}
GlobalManagedPackage = FindOrAddManagedPackage(FCSNamespace(TEXT("UnrealSharp")));
// Initialize the property factory. This is used to create properties for managed structs/classes/functions.
FCSPropertyFactory::Initialize();
// Try to load the user assembly. Can be empty if the user hasn't created any csproj yet.
LoadAllUserAssemblies();
FModuleManager::Get().OnModulesChanged().AddUObject(this, &UCSManager::OnModulesChanged);
}
bool UCSManager::InitializeDotNetRuntime()
{
if (!LoadRuntimeHost())
{
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load Runtime Host"));
return false;
}
load_assembly_and_get_function_pointer_fn LoadAssemblyAndGetFunctionPointer = InitializeNativeHost();
if (!LoadAssemblyAndGetFunctionPointer)
{
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to initialize Runtime Host. Check logs for more details."));
return false;
}
const FString EntryPointClassName = TEXT("UnrealSharp.Plugins.Main, UnrealSharp.Plugins");
const FString EntryPointFunctionName = TEXT("InitializeUnrealSharp");
const FString UnrealSharpLibraryAssembly = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetUnrealSharpPluginsPath());
const FString UserWorkingDirectory = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetUserAssemblyDirectory());
FInitializeRuntimeHost InitializeUnrealSharp = nullptr;
const int32 ErrorCode = LoadAssemblyAndGetFunctionPointer(PLATFORM_STRING(*UnrealSharpLibraryAssembly),
PLATFORM_STRING(*EntryPointClassName),
PLATFORM_STRING(*EntryPointFunctionName),
UNMANAGEDCALLERSONLY_METHOD,
nullptr,
reinterpret_cast<void**>(&InitializeUnrealSharp));
if (ErrorCode != 0)
{
UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to load assembly: {0}", ErrorCode);
return false;
}
// Entry point to C# to initialize UnrealSharp
if (!InitializeUnrealSharp(*UserWorkingDirectory,
*UnrealSharpLibraryAssembly,
&ManagedPluginsCallbacks,
(const void*)&FCSBindsManager::GetBoundFunction,
&FCSManagedCallbacks::ManagedCallbacks))
{
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to initialize UnrealSharp!"));
return false;
}
return true;
}
bool UCSManager::LoadRuntimeHost()
{
const FString RuntimeHostPath = FCSProcHelper::GetRuntimeHostPath();
if (!FPaths::FileExists(RuntimeHostPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("Couldn't find Hostfxr.dll"));
return false;
}
RuntimeHost = FPlatformProcess::GetDllHandle(*RuntimeHostPath);
if (RuntimeHost == nullptr)
{
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to get the RuntimeHost DLL handle!"));
return false;
}
#if defined(_WIN32)
void* DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_dotnet_command_line"));
Hostfxr_Initialize_For_Dotnet_Command_Line = static_cast<hostfxr_initialize_for_dotnet_command_line_fn>(DLLHandle);
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_runtime_config"));
Hostfxr_Initialize_For_Runtime_Config = static_cast<hostfxr_initialize_for_runtime_config_fn>(DLLHandle);
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_get_runtime_delegate"));
Hostfxr_Get_Runtime_Delegate = static_cast<hostfxr_get_runtime_delegate_fn>(DLLHandle);
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_close"));
Hostfxr_Close = static_cast<hostfxr_close_fn>(DLLHandle);
#else
Hostfxr_Initialize_For_Dotnet_Command_Line = (hostfxr_initialize_for_dotnet_command_line_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_dotnet_command_line"));
Hostfxr_Initialize_For_Runtime_Config = (hostfxr_initialize_for_runtime_config_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_runtime_config"));
Hostfxr_Get_Runtime_Delegate = (hostfxr_get_runtime_delegate_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_get_runtime_delegate"));
Hostfxr_Close = (hostfxr_close_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_close"));
#endif
return Hostfxr_Initialize_For_Dotnet_Command_Line && Hostfxr_Get_Runtime_Delegate && Hostfxr_Close && Hostfxr_Initialize_For_Runtime_Config;
}
bool UCSManager::LoadAllUserAssemblies()
{
TArray<FString> UserAssemblyPaths;
FCSProcHelper::GetAssemblyPathsByLoadOrder(UserAssemblyPaths, true);
if (UserAssemblyPaths.IsEmpty())
{
return true;
}
for (const FString& UserAssemblyPath : UserAssemblyPaths)
{
LoadAssemblyByPath(UserAssemblyPath);
}
OnAssembliesLoaded.Broadcast();
return true;
}
void UCSManager::NotifyUObjectDeleted(const UObjectBase* Object, int32 Index)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::NotifyUObjectDeleted);
TSharedPtr<FGCHandle> Handle;
if (!ManagedObjectHandles.RemoveAndCopyValueByHash(Index, Index, Handle))
{
return;
}
UCSAssembly* Assembly = FindOwningAssembly(Object->GetClass());
if (!IsValid(Assembly))
{
FString ObjectName = Object->GetFName().ToString();
FString ClassName = Object->GetClass()->GetFName().ToString();
UE_LOG(LogUnrealSharp, Error, TEXT("Failed to find owning assembly for object %s with class %s. Will cause managed memory leak."), *ObjectName, *ClassName);
return;
}
TSharedPtr<const FGCHandle> AssemblyHandle = Assembly->GetManagedAssemblyHandle();
Handle->Dispose(AssemblyHandle->GetHandle());
TMap<uint32, TSharedPtr<FGCHandle>>* FoundHandles = ManagedInterfaceWrappers.FindByHash(Index, Index);
if (FoundHandles == nullptr)
{
return;
}
for (auto &[Key, Value] : *FoundHandles)
{
Value->Dispose(AssemblyHandle->GetHandle());
}
FoundHandles->Empty();
ManagedInterfaceWrappers.Remove(Index);
}
void UCSManager::OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason)
{
if (InModuleChangeReason != EModuleChangeReason::ModuleLoaded)
{
return;
}
TryInitializeDynamicSubsystems();
}
void UCSManager::TryInitializeDynamicSubsystems()
{
// Try to activate Editor/EngineSubsystems
for (int32 i = PendingDynamicSubsystemClasses.Num() - 1; i >= 0; --i)
{
TSubclassOf<UDynamicSubsystem> SubsystemClass = PendingDynamicSubsystemClasses[i];
if (!IsValid(SubsystemClass))
{
UE_LOG(LogUnrealSharp, Warning, TEXT("Tried to activate an invalid dynamic subsystem class"));
PendingDynamicSubsystemClasses.RemoveAt(i);
continue;
}
FSubsystemCollectionBase::ActivateExternalSubsystem(SubsystemClass);
// Unfortunately no better way to check if the subsystems actually registered.
{
if (SubsystemClass->IsChildOf(UEngineSubsystem::StaticClass()))
{
if (IsValid(GEngine) && GEngine->GetEngineSubsystemBase(SubsystemClass.Get()))
{
PendingDynamicSubsystemClasses.RemoveAt(i);
}
}
#if WITH_EDITOR
else if (SubsystemClass->IsChildOf(UEditorSubsystem::StaticClass()))
{
if (IsValid(GEditor) && GEditor->GetEditorSubsystemBase(SubsystemClass.Get()))
{
PendingDynamicSubsystemClasses.RemoveAt(i);
}
}
#endif
}
}
}
load_assembly_and_get_function_pointer_fn UCSManager::InitializeNativeHost() const
{
#if WITH_EDITOR
FString DotNetPath = FCSProcHelper::GetDotNetDirectory();
#else
FString DotNetPath = FCSProcHelper::GetPluginAssembliesPath();
#endif
if (!FPaths::DirectoryExists(DotNetPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("Dotnet directory does not exist at: %s"), *DotNetPath);
return nullptr;
}
FString RuntimeHostPath = FCSProcHelper::GetRuntimeHostPath();
if (!FPaths::FileExists(RuntimeHostPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("Runtime host path does not exist at: %s"), *RuntimeHostPath);
return nullptr;
}
UE_LOG(LogUnrealSharp, Log, TEXT("DotNetPath: %s"), *DotNetPath);
UE_LOG(LogUnrealSharp, Log, TEXT("RuntimeHostPath: %s"), *RuntimeHostPath);
hostfxr_initialize_parameters InitializeParameters;
InitializeParameters.dotnet_root = PLATFORM_STRING(*DotNetPath);
InitializeParameters.host_path = PLATFORM_STRING(*RuntimeHostPath);
InitializeParameters.size = sizeof(hostfxr_initialize_parameters);
hostfxr_handle HostFXR_Handle = nullptr;
int32 ErrorCode = 0;
#if WITH_EDITOR
FString RuntimeConfigPath = FCSProcHelper::GetRuntimeConfigPath();
if (!FPaths::FileExists(RuntimeConfigPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("No runtime config found"));
return nullptr;
}
#if defined(_WIN32)
ErrorCode = Hostfxr_Initialize_For_Runtime_Config(PLATFORM_STRING(*RuntimeConfigPath), &InitializeParameters, &HostFXR_Handle);
#else
ErrorCode = Hostfxr_Initialize_For_Runtime_Config(PLATFORM_STRING(*RuntimeConfigPath), nullptr, &HostFXR_Handle);
#endif
#else
FString PluginAssemblyPath = FCSProcHelper::GetUnrealSharpPluginsPath();
if (!FPaths::FileExists(PluginAssemblyPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("UnrealSharp.Plugins.dll does not exist at: %s"), *PluginAssemblyPath);
return nullptr;
}
std::vector Args { PLATFORM_STRING(*PluginAssemblyPath) };
#if defined(_WIN32)
ErrorCode = Hostfxr_Initialize_For_Dotnet_Command_Line(Args.size(), Args.data(), &InitializeParameters, &HostFXR_Handle);
#else
ErrorCode = Hostfxr_Initialize_For_Dotnet_Command_Line(Args.size(), const_cast<const char**>(Args.data()), &InitializeParameters, &HostFXR_Handle);
#endif
#endif
if (ErrorCode != 0)
{
UE_LOG(LogUnrealSharp, Error, TEXT("hostfxr_initialize_for_runtime_config failed with code: %d"), ErrorCode);
return nullptr;
}
void* LoadAssemblyAndGetFunctionPointer = nullptr;
ErrorCode = Hostfxr_Get_Runtime_Delegate(HostFXR_Handle, hdt_load_assembly_and_get_function_pointer, &LoadAssemblyAndGetFunctionPointer);
Hostfxr_Close(HostFXR_Handle);
if (ErrorCode != 0 || !LoadAssemblyAndGetFunctionPointer)
{
UE_LOG(LogUnrealSharp, Error, TEXT("hostfxr_get_runtime_delegate failed with code: %d"), ErrorCode);
return nullptr;
}
return (load_assembly_and_get_function_pointer_fn)LoadAssemblyAndGetFunctionPointer;
}
UCSAssembly* UCSManager::LoadAssemblyByPath(const FString& AssemblyPath, bool bIsCollectible)
{
if (!FPaths::FileExists(AssemblyPath))
{
UE_LOG(LogUnrealSharp, Error, TEXT("Assembly path does not exist: %s"), *AssemblyPath);
return nullptr;
}
FString AssemblyName = FPaths::GetBaseFilename(AssemblyPath);
UCSAssembly* ExistingAssembly = FindAssembly(FName(*AssemblyName));
if (IsValid(ExistingAssembly) && ExistingAssembly->IsValidAssembly())
{
UE_LOGFMT(LogUnrealSharp, Display, "Assembly {AssemblyName} is already loaded.", *AssemblyName);
return ExistingAssembly;
}
UCSAssembly* NewAssembly = NewObject<UCSAssembly>(this, *AssemblyName);
NewAssembly->SetAssemblyPath(AssemblyPath);
LoadedAssemblies.Add(NewAssembly->GetAssemblyName(), NewAssembly);
if (!NewAssembly->LoadAssembly(bIsCollectible))
{
return nullptr;
}
OnManagedAssemblyLoaded.Broadcast(NewAssembly->GetAssemblyName());
UE_LOGFMT(LogUnrealSharp, Display, "Successfully loaded AssemblyHandle with path {AssemblyPath}.", *AssemblyPath);
return NewAssembly;
}
UCSAssembly* UCSManager::LoadUserAssemblyByName(const FName AssemblyName, bool bIsCollectible)
{
FString AssemblyPath = FPaths::Combine(FCSProcHelper::GetUserAssemblyDirectory(), AssemblyName.ToString() + ".dll");
return LoadAssemblyByPath(AssemblyPath, bIsCollectible);
}
UCSAssembly* UCSManager::LoadPluginAssemblyByName(const FName AssemblyName, bool bIsCollectible)
{
FString AssemblyPath = FPaths::Combine(FCSProcHelper::GetPluginAssembliesPath(), AssemblyName.ToString() + ".dll");
return LoadAssemblyByPath(AssemblyPath, bIsCollectible);
}
UCSAssembly* UCSManager::FindOwningAssembly(UClass* Class)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
if (ICSManagedTypeInterface* ManagedType = FCSClassUtilities::GetManagedType(Class))
{
// Fast access to the owning assembly for managed types.
return ManagedType->GetOwningAssembly();
}
Class = FCSClassUtilities::GetFirstNativeClass(Class);
uint32 ClassID = Class->GetUniqueID();
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
if (IsValid(Assembly))
{
return Assembly;
}
return FindOwningAssemblySlow(Class);
}
UCSAssembly * UCSManager::FindOwningAssembly(UScriptStruct* Struct)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
if (const ICSManagedTypeInterface* ManagedType = Cast<ICSManagedTypeInterface>(Struct); ManagedType != nullptr)
{
// Fast access to the owning assembly for managed types.
return ManagedType->GetOwningAssembly();
}
if (const UUserDefinedStruct* UserStruct = Cast<UUserDefinedStruct>(Struct); UserStruct != nullptr)
{
// This is a Blueprint Struct and we can't use it
return nullptr;
}
uint32 ClassID = Struct->GetUniqueID();
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
if (IsValid(Assembly))
{
return Assembly;
}
return FindOwningAssemblySlow(Struct);
}
UCSAssembly* UCSManager::FindOwningAssembly(UEnum* Enum)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
if (const ICSManagedTypeInterface* ManagedType = Cast<ICSManagedTypeInterface>(Enum); ManagedType != nullptr)
{
// Fast access to the owning assembly for managed types.
return ManagedType->GetOwningAssembly();
}
if (const UUserDefinedEnum* UserEnum = Cast<UUserDefinedEnum>(Enum); UserEnum != nullptr)
{
// This is a Blueprint Enum and we can't use it
return nullptr;
}
uint32 ClassID = Enum->GetUniqueID();
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
if (IsValid(Assembly))
{
return Assembly;
}
return FindOwningAssemblySlow(Enum);
}
UCSAssembly* UCSManager::FindOwningAssemblySlow(UField *Field)
{
// Slow path for native classes. This runs once per new native class.
const FCSFieldName ClassName = FCSFieldName(Field);
for (TPair<FName, TObjectPtr<UCSAssembly>>& LoadedAssembly : LoadedAssemblies)
{
if (TSharedPtr<FGCHandle> TypeHandle = LoadedAssembly.Value->TryFindTypeHandle(ClassName); !TypeHandle.IsValid() || TypeHandle->IsNull())
{
continue;
}
uint32 FieldID = Field->GetUniqueID();
NativeClassToAssemblyMap.AddByHash(FieldID, FieldID, LoadedAssembly.Value);
return LoadedAssembly.Value;
}
return nullptr;
}
FGCHandle UCSManager::FindManagedObject(const UObject* Object)
{
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindManagedObject);
if (!IsValid(Object))
{
return FGCHandle::Null();
}
uint32 ObjectID = Object->GetUniqueID();
if (TSharedPtr<FGCHandle>* FoundHandle = ManagedObjectHandles.FindByHash(ObjectID, ObjectID))
{
#if WITH_EDITOR
// During full hot reload only the managed objects are GCd as we reload the assemblies.
// So the C# counterpart can be invalid even if the handle can be found, so we need to create a new one.
TSharedPtr<FGCHandle> HandlePtr = *FoundHandle;
if (HandlePtr.IsValid() && !HandlePtr->IsNull())
{
return *HandlePtr;
}
#else
return **FoundHandle;
#endif
}
// No existing handle found, we need to create a new managed object.
UCSAssembly* OwningAssembly = FindOwningAssembly(Object->GetClass());
if (!IsValid(OwningAssembly))
{
UE_LOGFMT(LogUnrealSharp, Error, "Failed to find assembly for {0}", *Object->GetName());
return FGCHandle::Null();
}
return *OwningAssembly->CreateManagedObject(Object);
}
FGCHandle UCSManager::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass)
{
if (!Object->GetClass()->ImplementsInterface(InterfaceClass))
{
return FGCHandle::Null();
}
// No existing handle found, we need to create a new managed object.
UCSAssembly* OwningAssembly = FindOwningAssembly(InterfaceClass);
if (!IsValid(OwningAssembly))
{
UE_LOGFMT(LogUnrealSharp, Error, "Failed to find assembly for {0}", *InterfaceClass->GetName());
return FGCHandle::Null();
}
TSharedPtr<FGCHandle> FoundHandle = OwningAssembly->FindOrCreateManagedInterfaceWrapper(Object, InterfaceClass);
if (!FoundHandle.IsValid())
{
return FGCHandle::Null();
}
return *FoundHandle;
}