173 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			173 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#pragma once
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#include "CSManagedGCHandle.h"
							 | 
						|||
| 
								 | 
							
								#include "UnrealSharpCore.h"
							 | 
						|||
| 
								 | 
							
								#include "Logging/StructuredLog.h"
							 | 
						|||
| 
								 | 
							
								#include "TypeGenerator/Register/MetaData/CSTypeReferenceMetaData.h"
							 | 
						|||
| 
								 | 
							
								#include "Utils/CSClassUtilities.h"
							 | 
						|||
| 
								 | 
							
								#include "CSAssembly.generated.h"
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								#if !defined(_WIN32)
							 | 
						|||
| 
								 | 
							
								#define __stdcall
							 | 
						|||
| 
								 | 
							
								#endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								struct FCSClassInfo;
							 | 
						|||
| 
								 | 
							
								struct FCSManagedMethod;
							 | 
						|||
| 
								 | 
							
								class UCSClass;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * Represents a managed assembly.
							 | 
						|||
| 
								 | 
							
								 * This class is responsible for loading and unloading the assembly, as well as managing all types that are defined in the C# assembly.
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								UCLASS()
							 | 
						|||
| 
								 | 
							
								class UCSAssembly : public UObject
							 | 
						|||
| 
								 | 
							
								{
							 | 
						|||
| 
								 | 
							
									GENERATED_BODY()
							 | 
						|||
| 
								 | 
							
								public:
							 | 
						|||
| 
								 | 
							
									void SetAssemblyPath(const FStringView InAssemblyPath);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									UNREALSHARPCORE_API bool LoadAssembly(bool bIsCollectible = true);
							 | 
						|||
| 
								 | 
							
									UNREALSHARPCORE_API bool UnloadAssembly();
							 | 
						|||
| 
								 | 
							
									UNREALSHARPCORE_API bool IsValidAssembly() const { return ManagedAssemblyHandle.IsValid() && !ManagedAssemblyHandle->IsNull(); }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									FName GetAssemblyName() const { return AssemblyName; }
							 | 
						|||
| 
								 | 
							
									const FString& GetAssemblyPath() const { return AssemblyPath; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									bool IsLoading() const { return bIsLoading; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> TryFindTypeHandle(const FCSFieldName& FieldName);
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> GetManagedMethod(const TSharedPtr<FGCHandle>& TypeHandle, const FString& MethodName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									template<typename T = FCSManagedTypeInfo>
							 | 
						|||
| 
								 | 
							
									TSharedPtr<T> FindOrAddTypeInfo(UClass* Field)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										if (ICSManagedTypeInterface* ManagedClass = FCSClassUtilities::GetManagedType(Field))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											return ManagedClass->GetManagedTypeInfo<T>();
							 | 
						|||
| 
								 | 
							
										}	
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
										FCSFieldName FieldName(Field);
							 | 
						|||
| 
								 | 
							
										return FindOrAddTypeInfo<T>(FieldName);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									template<typename T = FCSManagedTypeInfo>
							 | 
						|||
| 
								 | 
							
									TSharedPtr<T> FindOrAddTypeInfo(const FCSFieldName& ClassName)
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindOrAddClassInfo);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										TSharedPtr<FCSManagedTypeInfo>& TypeInfo = AllTypes.FindOrAdd(ClassName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										// Native types are populated on the go when they are needed for managed code execution.
							 | 
						|||
| 
								 | 
							
										if (!TypeInfo.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											UField* Field = TryFindField(ClassName);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											if (!IsValid(Field))
							 | 
						|||
| 
								 | 
							
											{
							 | 
						|||
| 
								 | 
							
												UE_LOGFMT(LogUnrealSharp, Error, "Failed to find native class: {0}", *ClassName.GetName());
							 | 
						|||
| 
								 | 
							
												return nullptr;
							 | 
						|||
| 
								 | 
							
											}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
											TypeInfo = MakeShared<FCSManagedTypeInfo>(Field, this);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if constexpr (std::is_same_v<T, FCSManagedTypeInfo>)
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											return TypeInfo;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
										else
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											return StaticCastSharedPtr<T>(TypeInfo);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									template<typename T = FCSManagedTypeInfo>
							 | 
						|||
| 
								 | 
							
									TSharedPtr<T> FindTypeInfo(const FCSFieldName& FieldName) const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindClassInfo);
							 | 
						|||
| 
								 | 
							
										static_assert(TIsDerivedFrom<T, FCSManagedTypeInfo>::Value, "T must be a FCSManagedTypeInfo-derived type.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										const TSharedPtr<FCSManagedTypeInfo>* TypeInfo = AllTypes.Find(FieldName);
							 | 
						|||
| 
								 | 
							
										if (TypeInfo && TypeInfo->IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											return StaticCastSharedPtr<T>(*TypeInfo);
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										return nullptr;
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									template<typename T = UField>
							 | 
						|||
| 
								 | 
							
									T* FindType(const FCSFieldName& FieldName) const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindType);
							 | 
						|||
| 
								 | 
							
										static_assert(TIsDerivedFrom<T, UField>::Value, "T must be a UField-derived type.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										TSharedPtr<FCSManagedTypeInfo> TypeInfo = AllTypes.FindRef(FieldName);
							 | 
						|||
| 
								 | 
							
										if (TypeInfo.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											return Cast<T>(TypeInfo->StartBuildingManagedType());
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										return TryFindField<T>(FieldName);
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Creates a C# counterpart for the given UObject.
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> CreateManagedObject(const UObject* Object);
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Add a class that is waiting for its parent class to be loaded before it can be created.
							 | 
						|||
| 
								 | 
							
									void AddPendingClass(const FCSTypeReferenceMetaData& ParentClass, FCSClassInfo* NewClass);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									TSharedPtr<const FGCHandle> GetManagedAssemblyHandle() const { return ManagedAssemblyHandle; }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								private:
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									bool ProcessTypeMetadata();
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									void OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason);
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									template<typename T = UField>
							 | 
						|||
| 
								 | 
							
									T* TryFindField(const FCSFieldName FieldName) const
							 | 
						|||
| 
								 | 
							
									{
							 | 
						|||
| 
								 | 
							
										TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::TryFindField);
							 | 
						|||
| 
								 | 
							
										static_assert(TIsDerivedFrom<T, UObject>::Value, "T must be a UObject-derived type.");
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										if (!FieldName.IsValid())
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											UE_LOGFMT(LogUnrealSharp, Warning, "Invalid field name: {0}", *FieldName.GetName());
							 | 
						|||
| 
								 | 
							
											return nullptr;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										UPackage* Package = FieldName.GetPackage();
							 | 
						|||
| 
								 | 
							
										if (!IsValid(Package))
							 | 
						|||
| 
								 | 
							
										{
							 | 
						|||
| 
								 | 
							
											UE_LOGFMT(LogUnrealSharp, Warning, "Failed to find package for field: {0}", *FieldName.GetName());
							 | 
						|||
| 
								 | 
							
											return nullptr;
							 | 
						|||
| 
								 | 
							
										}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
										return FindObject<T>(Package, *FieldName.GetName());
							 | 
						|||
| 
								 | 
							
									}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// All Unreal types that are defined in this assembly.
							 | 
						|||
| 
								 | 
							
									TMap<FCSFieldName, TSharedPtr<FCSManagedTypeInfo>> AllTypes;
							 | 
						|||
| 
								 | 
							
									
							 | 
						|||
| 
								 | 
							
									// All handles allocated by this assembly. Handles to types, methods, objects.
							 | 
						|||
| 
								 | 
							
									TArray<TSharedPtr<FGCHandle>> AllocatedManagedHandles;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Handles to all allocated UTypes (UClass/UStruct, etc) that are defined in this assembly.
							 | 
						|||
| 
								 | 
							
									TMap<FCSFieldName, TSharedPtr<FGCHandle>> ManagedClassHandles;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Pending classes that are waiting for their parent class to be loaded by the engine.
							 | 
						|||
| 
								 | 
							
									TMap<FCSTypeReferenceMetaData, TSet<FCSClassInfo*>> PendingClasses;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Handle to the Assembly object in C#.
							 | 
						|||
| 
								 | 
							
									TSharedPtr<FGCHandle> ManagedAssemblyHandle;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Full path to the assembly file.
							 | 
						|||
| 
								 | 
							
									FString AssemblyPath;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									// Assembly file name without the path.
							 | 
						|||
| 
								 | 
							
									FName AssemblyName;
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
									bool bIsLoading = false;
							 | 
						|||
| 
								 | 
							
								};
							 |