679 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			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;
							 | 
						|||
| 
								 | 
							
								}
							 |