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; | |||
|  | }; |