382 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			382 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#include "CSAssembly.h"
							 | 
						|||
| 
								 | 
							
								#include "UnrealSharpCore.h"
							 | 
						|||
| 
								 | 
							
								#include "Misc/Paths.h"
							 | 
						|||
| 
								 | 
							
								#include "CSManager.h"
							 | 
						|||
| 
								 | 
							
								#include "CSUnrealSharpSettings.h"
							 | 
						|||
| 
								 | 
							
								#include "Logging/StructuredLog.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/CSClass.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/CSEnum.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/CSInterface.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/CSScriptStruct.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSClassMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSDelegateMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSEnumMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSInterfaceMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSStructMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/TypeInfo/CSClassInfo.h"
							 | 
						|||
| 
								 | 
							
								#include "Utils/CSClassUtilities.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void UCSAssembly::SetAssemblyPath(const FStringView InAssemblyPath)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!AssemblyPath.IsEmpty())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									AssemblyPath = FPaths::ConvertRelativePathToFull(InAssemblyPath.GetData());
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if defined(_WIN32)
							 | 
						|||
| 
								 | 
							
									// Replace forward slashes with backslashes
							 | 
						|||
| 
								 | 
							
									AssemblyPath.ReplaceInline(TEXT("/"), TEXT("\\"));
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									AssemblyName = *FPaths::GetBaseFilename(AssemblyPath);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								bool UCSAssembly::LoadAssembly(bool bisCollectible)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString(TEXT("UCSAssembly::LoadAssembly: " + AssemblyName.ToString())));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (IsValidAssembly())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Display, TEXT("%s is already loaded"), *AssemblyPath);
							 | 
						|||
| 
								 | 
							
										return true;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!FPaths::FileExists(AssemblyPath))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Display, TEXT("%s doesn't exist"), *AssemblyPath);
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									bIsLoading = true;
							 | 
						|||
| 
								 | 
							
									FGCHandle NewHandle = UCSManager::Get().GetManagedPluginsCallbacks().LoadPlugin(*AssemblyPath, bisCollectible);
							 | 
						|||
| 
								 | 
							
									NewHandle.Type = GCHandleType::WeakHandle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (NewHandle.IsNull())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load: %s"), *AssemblyPath);
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									ManagedAssemblyHandle = MakeShared<FGCHandle>(NewHandle);
							 | 
						|||
| 
								 | 
							
									FModuleManager::Get().OnModulesChanged().AddUObject(this, &UCSAssembly::OnModulesChanged);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (ProcessTypeMetadata())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										for (const TPair<FCSFieldName, TSharedPtr<FCSManagedTypeInfo>>& NameToTypeInfo : AllTypes)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											NameToTypeInfo.Value->StartBuildingManagedType();
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									bIsLoading = false;
							 | 
						|||
| 
								 | 
							
									UCSManager::Get().OnManagedAssemblyLoadedEvent().Broadcast(AssemblyName);
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								template <typename T, typename MetaDataType>
							 | 
						|||
| 
								 | 
							
								void RegisterMetaData(UCSAssembly* OwningAssembly, const TSharedPtr<FJsonValue>& MetaData,
							 | 
						|||
| 
								 | 
							
									TMap<FCSFieldName,
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FCSManagedTypeInfo>>& Map,
							 | 
						|||
| 
								 | 
							
									UClass* FieldType,
							 | 
						|||
| 
								 | 
							
									TFunction<void(TSharedPtr<FCSManagedTypeInfo>)> OnRebuild = nullptr)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									const TSharedPtr<FJsonObject>& MetaDataObject = MetaData->AsObject();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const FString Name= MetaDataObject->GetStringField(TEXT("Name"));
							 | 
						|||
| 
								 | 
							
									const FString Namespace = MetaDataObject->GetStringField(TEXT("Namespace"));
							 | 
						|||
| 
								 | 
							
									const FCSFieldName FullName(*Name, *Namespace);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FCSManagedTypeInfo> ExistingValue = Map.FindRef(FullName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (ExistingValue.IsValid())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// Parse fresh metadata and update the existing info
							 | 
						|||
| 
								 | 
							
										MetaDataType NewMeta;
							 | 
						|||
| 
								 | 
							
										NewMeta.SerializeFromJson(MetaDataObject);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (ExistingValue->GetStructureState() == HasChangedStructure || NewMeta != *ExistingValue->GetTypeMetaData<MetaDataType>())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											TSharedPtr<MetaDataType> MetaDataPtr = MakeShared<MetaDataType>(NewMeta);
							 | 
						|||
| 
								 | 
							
											ExistingValue->SetTypeMetaData(MetaDataPtr);
							 | 
						|||
| 
								 | 
							
											ExistingValue->SetStructureState(HasChangedStructure);
							 | 
						|||
| 
								 | 
							
											
							 | 
						|||
| 
								 | 
							
											if (OnRebuild)
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												OnRebuild(ExistingValue);
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									else
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										TSharedPtr<MetaDataType> ParsedMeta = MakeShared<MetaDataType>();
							 | 
						|||
| 
								 | 
							
										ParsedMeta->SerializeFromJson(MetaDataObject);
							 | 
						|||
| 
								 | 
							
										
							 | 
						|||
| 
								 | 
							
										TSharedPtr<T> NewValue = MakeShared<T>(ParsedMeta, OwningAssembly, FieldType);
							 | 
						|||
| 
								 | 
							
										Map.Add(FullName, NewValue);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								bool UCSAssembly::ProcessTypeMetadata()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::ProcessTypeMetadata);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const FString MetadataPath = FPaths::ChangeExtension(AssemblyPath, "metadata.json");
							 | 
						|||
| 
								 | 
							
									if (!FPaths::FileExists(MetadataPath))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return true;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FString JsonString;
							 | 
						|||
| 
								 | 
							
									if (!FFileHelper::LoadFileToString(JsonString, *MetadataPath))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load MetaDataPath at: %s"), *MetadataPath);
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FJsonObject> JsonObject;
							 | 
						|||
| 
								 | 
							
									if (!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), JsonObject) || !JsonObject.IsValid())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to parse JSON at: %s"), *MetadataPath);
							 | 
						|||
| 
								 | 
							
										return false;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									UCSManager& Manager = UCSManager::Get();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const TArray<TSharedPtr<FJsonValue>>& StructMetaData = JsonObject->GetArrayField(TEXT("StructMetaData"));
							 | 
						|||
| 
								 | 
							
									for (const TSharedPtr<FJsonValue>& MetaData : StructMetaData)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										RegisterMetaData<FCSManagedTypeInfo, FCSStructMetaData>(this, MetaData, AllTypes, UCSScriptStruct::StaticClass());
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const TArray<TSharedPtr<FJsonValue>>& EnumMetaData = JsonObject->GetArrayField(TEXT("EnumMetaData"));
							 | 
						|||
| 
								 | 
							
									for (const TSharedPtr<FJsonValue>& MetaData : EnumMetaData)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										RegisterMetaData<FCSManagedTypeInfo, FCSEnumMetaData>(this, MetaData, AllTypes, UCSEnum::StaticClass());
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const TArray<TSharedPtr<FJsonValue>>& InterfacesMetaData = JsonObject->GetArrayField(TEXT("InterfacesMetaData"));
							 | 
						|||
| 
								 | 
							
									for (const TSharedPtr<FJsonValue>& MetaData : InterfacesMetaData)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										RegisterMetaData<FCSManagedTypeInfo, FCSInterfaceMetaData>(this, MetaData, AllTypes, UCSInterface::StaticClass());
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const TArray<TSharedPtr<FJsonValue>>& DelegatesMetaData = JsonObject->GetArrayField(TEXT("DelegateMetaData"));
							 | 
						|||
| 
								 | 
							
									for (const TSharedPtr<FJsonValue>& MetaData : DelegatesMetaData)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										RegisterMetaData<FCSManagedTypeInfo, FCSDelegateMetaData>(this, MetaData, AllTypes, UDelegateFunction::StaticClass());
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									const TArray<TSharedPtr<FJsonValue>>& ClassesMetaData = JsonObject->GetArrayField(TEXT("ClassMetaData"));
							 | 
						|||
| 
								 | 
							
									for (const TSharedPtr<FJsonValue>& MetaData : ClassesMetaData)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										RegisterMetaData<FCSClassInfo, FCSClassMetaData>(this, MetaData, AllTypes, UCSClass::StaticClass(),
							 | 
						|||
| 
								 | 
							
								         [&Manager](const TSharedPtr<FCSManagedTypeInfo>& ClassInfo)
							 | 
						|||
| 
								 | 
							
								         {
							 | 
						|||
| 
								 | 
							
								             // Structure has been changed. We must trigger full reload on all managed classes that derive from this class.
							 | 
						|||
| 
								 | 
							
								             TArray<UClass*> DerivedClasses;
							 | 
						|||
| 
								 | 
							
								             GetDerivedClasses(ClassInfo->GetFieldChecked<UClass>(), DerivedClasses);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								             for (UClass* DerivedClass : DerivedClasses)
							 | 
						|||
| 
								 | 
							
								             {
							 | 
						|||
| 
								 | 
							
								                 if (!Manager.IsManagedType(DerivedClass))
							 | 
						|||
| 
								 | 
							
								                 {
							 | 
						|||
| 
								 | 
							
								                     continue;
							 | 
						|||
| 
								 | 
							
								                 }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								                 UCSClass* ManagedClass = static_cast<UCSClass*>(DerivedClass);
							 | 
						|||
| 
								 | 
							
								                 TSharedPtr<FCSClassInfo> ChildClassInfo = ManagedClass->GetManagedTypeInfo<FCSClassInfo>();
							 | 
						|||
| 
								 | 
							
								                 ChildClassInfo->SetStructureState(HasChangedStructure);
							 | 
						|||
| 
								 | 
							
								             }
							 | 
						|||
| 
								 | 
							
								         });
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return true;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								bool UCSAssembly::UnloadAssembly()
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!IsValidAssembly())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// Assembly is already unloaded.
							 | 
						|||
| 
								 | 
							
										UE_LOGFMT(LogUnrealSharp, Display, "{0} is already unloaded", *AssemblyName.ToString());
							 | 
						|||
| 
								 | 
							
										return true;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString(TEXT("UCSAssembly::UnloadAssembly: " + AssemblyName.ToString())));
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FGCHandleIntPtr AssemblyHandle = ManagedAssemblyHandle->GetHandle();
							 | 
						|||
| 
								 | 
							
									for (TSharedPtr<FGCHandle>& Handle : AllocatedManagedHandles)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										Handle->Dispose(AssemblyHandle);
							 | 
						|||
| 
								 | 
							
										Handle.Reset();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									ManagedClassHandles.Reset();
							 | 
						|||
| 
								 | 
							
									AllocatedManagedHandles.Reset();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Don't need the assembly handle anymore, we use the path to unload the assembly.
							 | 
						|||
| 
								 | 
							
									ManagedAssemblyHandle->Dispose(ManagedAssemblyHandle->GetHandle());
							 | 
						|||
| 
								 | 
							
									ManagedAssemblyHandle.Reset();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    UCSManager::Get().OnManagedAssemblyUnloadedEvent().Broadcast(AssemblyName);
							 | 
						|||
| 
								 | 
							
									return UCSManager::Get().GetManagedPluginsCallbacks().UnloadPlugin(*AssemblyPath);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								TSharedPtr<FGCHandle> UCSAssembly::TryFindTypeHandle(const FCSFieldName& FieldName)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!IsValidAssembly())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (TSharedPtr<FGCHandle>* Handle = ManagedClassHandles.Find(FieldName))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return *Handle;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FString FullName = FieldName.GetFullName().ToString();
							 | 
						|||
| 
								 | 
							
									uint8* TypeHandle = FCSManagedCallbacks::ManagedCallbacks.LookupManagedType(ManagedAssemblyHandle->GetPointer(), *FullName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (!TypeHandle)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> AllocatedHandle = MakeShared<FGCHandle>(TypeHandle, GCHandleType::WeakHandle);
							 | 
						|||
| 
								 | 
							
									AllocatedManagedHandles.Add(AllocatedHandle);
							 | 
						|||
| 
								 | 
							
									ManagedClassHandles.Add(FieldName, AllocatedHandle);
							 | 
						|||
| 
								 | 
							
									return AllocatedHandle;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								TSharedPtr<FGCHandle> UCSAssembly::GetManagedMethod(const TSharedPtr<FGCHandle>& TypeHandle, const FString& MethodName)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (!TypeHandle.IsValid())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOGFMT(LogUnrealSharp, Error, "Type handle is invalid for method %s", *MethodName);
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									uint8* MethodHandle = FCSManagedCallbacks::ManagedCallbacks.LookupManagedMethod(TypeHandle->GetPointer(), *MethodName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (MethodHandle == nullptr)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UE_LOG(LogUnrealSharp, Error, TEXT("Failed to find managed method for %s"), *MethodName);
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> AllocatedHandle = MakeShared<FGCHandle>(MethodHandle, GCHandleType::WeakHandle);
							 | 
						|||
| 
								 | 
							
									AllocatedManagedHandles.Add(AllocatedHandle);
							 | 
						|||
| 
								 | 
							
									return AllocatedHandle;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								TSharedPtr<FGCHandle> UCSAssembly::CreateManagedObject(const UObject* Object)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::CreateManagedObject);
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									// Only managed/native classes have a C# counterpart.
							 | 
						|||
| 
								 | 
							
									UClass* Class = FCSClassUtilities::GetFirstNonBlueprintClass(Object->GetClass());
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FCSManagedTypeInfo> TypeInfo = FindOrAddTypeInfo(Class);
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> TypeHandle = TypeInfo->GetManagedTypeHandle();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TCHAR* Error = nullptr;
							 | 
						|||
| 
								 | 
							
									FGCHandle NewManagedObject = FCSManagedCallbacks::ManagedCallbacks.CreateNewManagedObject(Object, TypeHandle->GetPointer(), &Error);
							 | 
						|||
| 
								 | 
							
									NewManagedObject.Type = GCHandleType::StrongHandle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (NewManagedObject.IsNull())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// This should never happen. Potential issues: IL errors, typehandle is invalid.
							 | 
						|||
| 
								 | 
							
										UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to create managed counterpart for {0}:\n{1}", *Object->GetName(), Error);
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> Handle = MakeShared<FGCHandle>(NewManagedObject);
							 | 
						|||
| 
								 | 
							
									AllocatedManagedHandles.Add(Handle);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									uint32 ObjectID = Object->GetUniqueID();
							 | 
						|||
| 
								 | 
							
									UCSManager::Get().ManagedObjectHandles.AddByHash(ObjectID, ObjectID, Handle);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									return Handle;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								TSharedPtr<FGCHandle> UCSAssembly::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindOrCreateManagedInterfaceWrapper);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UClass* NonBlueprintClass = FCSClassUtilities::GetFirstNonBlueprintClass(InterfaceClass);
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FCSManagedTypeInfo> ClassInfo = FindOrAddTypeInfo(NonBlueprintClass);
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> TypeHandle = ClassInfo->GetManagedTypeHandle();
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									uint32 ObjectID = Object->GetUniqueID();
							 | 
						|||
| 
								 | 
							
								    TMap<uint32, TSharedPtr<FGCHandle>>& TypeMap = UCSManager::Get().ManagedInterfaceWrappers.FindOrAddByHash(ObjectID, ObjectID);
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									uint32 TypeId = InterfaceClass->GetUniqueID();
							 | 
						|||
| 
								 | 
							
									if (TSharedPtr<FGCHandle>* Existing = TypeMap.FindByHash(TypeId, TypeId))
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return *Existing;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								    TSharedPtr<FGCHandle>* ObjectHandle = UCSManager::Get().ManagedObjectHandles.FindByHash(ObjectID, ObjectID);
							 | 
						|||
| 
								 | 
							
									if (ObjectHandle == nullptr)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								    
							 | 
						|||
| 
								 | 
							
									FGCHandle NewManagedObjectWrapper = FCSManagedCallbacks::ManagedCallbacks.CreateNewManagedObjectWrapper((*ObjectHandle)->GetPointer(), TypeHandle->GetPointer());
							 | 
						|||
| 
								 | 
							
									NewManagedObjectWrapper.Type = GCHandleType::StrongHandle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									if (NewManagedObjectWrapper.IsNull())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										// This should never happen. Potential issues: IL errors, typehandle is invalid.
							 | 
						|||
| 
								 | 
							
										UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to create managed counterpart for {0}", *Object->GetName());
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> Handle = MakeShared<FGCHandle>(NewManagedObjectWrapper);
							 | 
						|||
| 
								 | 
							
									AllocatedManagedHandles.Add(Handle);
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									TypeMap.AddByHash(TypeId, TypeId, Handle);
							 | 
						|||
| 
								 | 
							
									return Handle;
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void UCSAssembly::AddPendingClass(const FCSTypeReferenceMetaData& ParentClass, FCSClassInfo* NewClass)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									TSet<FCSClassInfo*>& PendingClass = PendingClasses.FindOrAdd(ParentClass);
							 | 
						|||
| 
								 | 
							
									PendingClass.Add(NewClass);
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								void UCSAssembly::OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason)
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									if (InModuleChangeReason != EModuleChangeReason::ModuleLoaded)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										return;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									int32 NumPendingClasses = PendingClasses.Num();
							 | 
						|||
| 
								 | 
							
									for (auto Itr = PendingClasses.CreateIterator(); Itr; ++Itr)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UClass* Class = Itr.Key().GetOwningClass();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!Class)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											// Class still not loaded from this module.
							 | 
						|||
| 
								 | 
							
											continue;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										for (FCSClassInfo* PendingClass : Itr.Value())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											PendingClass->StartBuildingManagedType();
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										Itr.RemoveCurrent();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if WITH_EDITOR
							 | 
						|||
| 
								 | 
							
									if (NumPendingClasses != PendingClasses.Num())
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										UCSManager::Get().OnProcessedPendingClassesEvent().Broadcast();
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								}
							 |