| @ -0,0 +1,49 @@ | ||||
| #include "CSAsyncActionBase.h" | ||||
| #include "UnrealSharpAsync.h" | ||||
|  | ||||
| void UCSAsyncActionBase::Destroy() | ||||
| { | ||||
| 	if (UGameInstance* GameInstance = GetWorld()->GetGameInstance()) | ||||
| 	{ | ||||
| 		GameInstance->UnregisterReferencedObject(this); | ||||
| 	} | ||||
|  | ||||
| 	ManagedCallback.Dispose(); | ||||
| 	MarkAsGarbage(); | ||||
| } | ||||
|  | ||||
| void UCSAsyncActionBase::InvokeManagedCallback(bool bDispose) | ||||
| { | ||||
| 	InvokeManagedCallback(this, bDispose); | ||||
| } | ||||
|  | ||||
| void UCSAsyncActionBase::InvokeManagedCallback(UObject* WorldContextObject, bool bDispose) | ||||
| { | ||||
|     ManagedCallback.Invoke(WorldContextObject, bDispose); | ||||
|  | ||||
|     if (bDispose) | ||||
|     { | ||||
|         Destroy(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void UCSAsyncActionBase::InitializeManagedCallback(FGCHandleIntPtr Callback) | ||||
| { | ||||
| 	ManagedCallback = FGCHandle(Callback, GCHandleType::WeakHandle); | ||||
|  | ||||
| 	if (UGameInstance* GameInstance = GetWorld()->GetGameInstance()) | ||||
| 	{ | ||||
| 		GameInstance->RegisterReferencedObject(this); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UUCSAsyncBaseExporter::InitializeAsyncObject(UCSAsyncActionBase* AsyncAction, FGCHandleIntPtr Callback) | ||||
| { | ||||
| 	if (!IsValid(AsyncAction)) | ||||
| 	{ | ||||
| 		UE_LOG(LogUnrealSharpAsync, Warning, TEXT("UUCSAsyncBaseExporter::InitializeAsyncObject: AsyncAction is null")); | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	AsyncAction->InitializeManagedCallback(Callback); | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| #include "CSAsyncLoadPrimaryDataAssets.h" | ||||
| #include "Engine/AssetManager.h" | ||||
|  | ||||
| void UCSAsyncLoadPrimaryDataAssets::LoadPrimaryDataAssets(const TArray<FPrimaryAssetId>& AssetIds, const TArray<FName>& AssetBundles) | ||||
| { | ||||
| 	UAssetManager& AssetManager = UAssetManager::Get(); | ||||
| 	AssetManager.LoadPrimaryAssets(AssetIds, AssetBundles, FStreamableDelegate::CreateUObject(this, &UCSAsyncLoadPrimaryDataAssets::OnPrimaryDataAssetsLoaded)); | ||||
| } | ||||
|  | ||||
| void UCSAsyncLoadPrimaryDataAssets::OnPrimaryDataAssetsLoaded() | ||||
| { | ||||
| 	InvokeManagedCallback(); | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| #include "CSAsyncLoadSoftObjectPtr.h" | ||||
| #include "Engine/AssetManager.h" | ||||
| #include "Engine/StreamableManager.h" | ||||
|  | ||||
| void UCSAsyncLoadSoftPtr::LoadSoftObjectPaths(const TArray<FSoftObjectPath>& SoftObjectPtr) | ||||
| { | ||||
| 	UAssetManager::Get().GetStreamableManager().RequestAsyncLoad(SoftObjectPtr, | ||||
| 	FStreamableDelegate::CreateUObject(this, &UCSAsyncLoadSoftPtr::OnAsyncLoadComplete)); | ||||
| } | ||||
|  | ||||
| void UCSAsyncLoadSoftPtr::OnAsyncLoadComplete() | ||||
| { | ||||
| 	InvokeManagedCallback(); | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,19 @@ | ||||
| #include "UnrealSharpAsync.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "FUnrealSharpAsyncModule" | ||||
|  | ||||
| DEFINE_LOG_CATEGORY(LogUnrealSharpAsync); | ||||
|  | ||||
| void FUnrealSharpAsyncModule::StartupModule() | ||||
| { | ||||
|      | ||||
| } | ||||
|  | ||||
| void FUnrealSharpAsyncModule::ShutdownModule() | ||||
| { | ||||
|      | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
|      | ||||
| IMPLEMENT_MODULE(FUnrealSharpAsyncModule, UnrealSharpAsync) | ||||
| @ -0,0 +1,36 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSManagedDelegate.h" | ||||
| #include "CSManagedGCHandle.h" | ||||
| #include "UnrealSharpBinds/Public/CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "CSAsyncActionBase.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPASYNC_API UCSAsyncActionBase : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UFUNCTION(meta = (ScriptMethod)) | ||||
| 	void Destroy(); | ||||
| protected: | ||||
| 	friend class UUCSAsyncBaseExporter; | ||||
|  | ||||
| 	void InvokeManagedCallback(bool bDispose = true); | ||||
|     void InvokeManagedCallback(UObject* WorldContextObject, bool bDispose = true); | ||||
| 	void InitializeManagedCallback(FGCHandleIntPtr Callback); | ||||
| 	 | ||||
| 	FCSManagedDelegate ManagedCallback; | ||||
| }; | ||||
|  | ||||
| UCLASS(meta = (InternalType)) | ||||
| class UUCSAsyncBaseExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void InitializeAsyncObject(UCSAsyncActionBase* AsyncAction, FGCHandleIntPtr Callback); | ||||
| }; | ||||
| @ -0,0 +1,18 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSAsyncActionBase.h" | ||||
| #include "CSAsyncLoadPrimaryDataAssets.generated.h" | ||||
|  | ||||
| UCLASS(meta = (InternalType)) | ||||
| class UCSAsyncLoadPrimaryDataAssets : public UCSAsyncActionBase | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UFUNCTION(meta =(ScriptMethod)) | ||||
| 	void LoadPrimaryDataAssets(const TArray<FPrimaryAssetId>& AssetIds, const TArray<FName>& AssetBundles); | ||||
| private: | ||||
| 	void OnPrimaryDataAssetsLoaded(); | ||||
| }; | ||||
| @ -0,0 +1,20 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSAsyncActionBase.h" | ||||
| #include "CSAsyncLoadSoftObjectPtr.generated.h" | ||||
|  | ||||
| UCLASS(meta = (InternalType)) | ||||
| class UCSAsyncLoadSoftPtr : public UCSAsyncActionBase | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UFUNCTION(meta = (ScriptMethod)) | ||||
| 	void LoadSoftObjectPaths(const TArray<FSoftObjectPath>& SoftObjectPtr); | ||||
| protected: | ||||
| 	void OnAsyncLoadComplete(); | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -0,0 +1,13 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "Modules/ModuleManager.h" | ||||
|  | ||||
| DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpAsync, Log, All); | ||||
|  | ||||
| class FUnrealSharpAsyncModule : public IModuleInterface | ||||
| { | ||||
| public: | ||||
|     virtual void StartupModule() override; | ||||
|     virtual void ShutdownModule() override; | ||||
| }; | ||||
| @ -0,0 +1,30 @@ | ||||
| using UnrealBuildTool; | ||||
|  | ||||
| public class UnrealSharpAsync : ModuleRules | ||||
| { | ||||
|     public UnrealSharpAsync(ReadOnlyTargetRules Target) : base(Target) | ||||
|     { | ||||
|         PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | ||||
|  | ||||
|         PublicDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "Core",  | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         PrivateDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "CoreUObject", | ||||
|                 "Engine", | ||||
|                 "Slate", | ||||
|                 "SlateCore", | ||||
|                 "UnrealSharpBinds", | ||||
|                 "UnrealSharpCore" | ||||
|             } | ||||
|         ); | ||||
|          | ||||
|         PublicDefinitions.Add("ForceAsEngineGlue=1"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,57 @@ | ||||
| #include "CSBindsManager.h" | ||||
| #include "UnrealSharpBinds.h" | ||||
|  | ||||
| FCSBindsManager* FCSBindsManager::BindsManagerInstance = nullptr; | ||||
|  | ||||
| FCSBindsManager* FCSBindsManager::Get() | ||||
| { | ||||
| 	if (!BindsManagerInstance) | ||||
| 	{ | ||||
| 		BindsManagerInstance = new FCSBindsManager(); | ||||
| 	} | ||||
|  | ||||
| 	return BindsManagerInstance; | ||||
| } | ||||
|  | ||||
| void FCSBindsManager::RegisterExportedFunction(const FName& ClassName, const FCSExportedFunction& ExportedFunction) | ||||
| { | ||||
| 	FCSBindsManager* Instance = Get(); | ||||
| 	TArray<FCSExportedFunction>& ExportedFunctions = Instance->ExportedFunctionsMap.FindOrAdd(ClassName); | ||||
| 	ExportedFunctions.Add(ExportedFunction); | ||||
| } | ||||
|  | ||||
| void* FCSBindsManager::GetBoundFunction(const TCHAR* InOuterName, const TCHAR* InFunctionName, int32 ManagedFunctionSize) | ||||
| { | ||||
| 	TRACE_CPUPROFILER_EVENT_SCOPE(UCSBindsManager::GetBoundFunction); | ||||
| 	 | ||||
| 	FCSBindsManager* Instance = Get(); | ||||
| 	FName ManagedOuterName = FName(InOuterName); | ||||
| 	FName ManagedFunctionName = FName(InFunctionName); | ||||
| 	 | ||||
| 	TArray<FCSExportedFunction>* ExportedFunctions = Instance->ExportedFunctionsMap.Find(ManagedOuterName); | ||||
|  | ||||
| 	if (!ExportedFunctions) | ||||
| 	{ | ||||
| 		UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: No exported functions found for %s"), InOuterName); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	for (FCSExportedFunction& NativeFunction : *ExportedFunctions) | ||||
| 	{ | ||||
| 		if (NativeFunction.Name != ManagedFunctionName) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 			 | ||||
| 		if (NativeFunction.Size != ManagedFunctionSize) | ||||
| 		{ | ||||
| 			UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: Function size mismatch for %s::%s."), InOuterName, InFunctionName); | ||||
| 			return nullptr; | ||||
| 		} | ||||
| 			 | ||||
| 		return NativeFunction.FunctionPointer; | ||||
| 	} | ||||
|  | ||||
| 	UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: No function found for %s.%s"), *ManagedOuterName.ToString(), *ManagedFunctionName.ToString()); | ||||
| 	return nullptr; | ||||
| } | ||||
| @ -0,0 +1,11 @@ | ||||
| #include "CSExportedFunction.h" | ||||
|  | ||||
| #include "CSBindsManager.h" | ||||
|  | ||||
| FCSExportedFunction::FCSExportedFunction(const FName& OuterName, const FName& Name, void* InFunctionPointer, int32 InSize): | ||||
| 	Name(Name), | ||||
| 	FunctionPointer(InFunctionPointer), | ||||
| 	Size(InSize) | ||||
| { | ||||
| 	FCSBindsManager::RegisterExportedFunction(OuterName, *this); | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| #include "UnrealSharpBinds.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "FUnrealSharpBindsModule" | ||||
|  | ||||
| DEFINE_LOG_CATEGORY(LogUnrealSharpBinds); | ||||
|  | ||||
| void FUnrealSharpBindsModule::StartupModule() | ||||
| { | ||||
| } | ||||
|  | ||||
| void FUnrealSharpBindsModule::ShutdownModule() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
|      | ||||
| IMPLEMENT_MODULE(FUnrealSharpBindsModule, UnrealSharpBinds) | ||||
| @ -0,0 +1,23 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CSExportedFunction.h" | ||||
|  | ||||
| // Native bound function. If you want to bind a function to C#, use this macro. | ||||
| // The managed delegate signature must match the native function signature + outer name, and all params need to be blittable. | ||||
| #define UNREALSHARP_FUNCTION() | ||||
|  | ||||
| class FCSBindsManager | ||||
| { | ||||
| public: | ||||
| 	 | ||||
| 	static FCSBindsManager* Get(); | ||||
| 	 | ||||
| 	UNREALSHARPBINDS_API static void RegisterExportedFunction(const FName& ClassName, const FCSExportedFunction& ExportedFunction); | ||||
|  | ||||
| 	UNREALSHARPBINDS_API static void* GetBoundFunction(const TCHAR* InOuterName, const TCHAR* InFunctionName, int32 ManagedFunctionSize); | ||||
|  | ||||
| private: | ||||
| 	FCSBindsManager() = default; | ||||
| 	static FCSBindsManager* BindsManagerInstance; | ||||
| 	TMap<FName, TArray<FCSExportedFunction>> ExportedFunctionsMap; | ||||
| }; | ||||
| @ -0,0 +1,50 @@ | ||||
| #pragma once | ||||
|  | ||||
| /** | ||||
|  * Thin wrapper around sizeof(T) used for getting the size of a function's arguments. | ||||
|  * @tparam T The type we want the size of | ||||
|  */ | ||||
| template <typename T> | ||||
| struct TArgSize | ||||
| { | ||||
| 	constexpr static size_t Size = sizeof(T); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Specialization for reference qualified types so we can get the size of the pointer instead of the object itself. | ||||
|  * @tparam T The type we want the size of | ||||
|  */ | ||||
| template <typename T> | ||||
| struct TArgSize<T&> | ||||
| { | ||||
| 	constexpr static size_t Size = sizeof(T*); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Constant expression for the size of an argument | ||||
|  * @tparam T The type we want the size of | ||||
|  */ | ||||
| template <typename T> | ||||
| constexpr size_t ArgSize = TArgSize<T>::Size; | ||||
|  | ||||
| template <typename ReturnType, typename... Args> | ||||
| constexpr size_t GetFunctionSize(ReturnType (*)(Args...)) | ||||
| { | ||||
| 	if constexpr (std::is_void_v<ReturnType>) | ||||
| 	{ | ||||
| 		return (ArgSize<Args> + ... + 0); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return ArgSize<ReturnType> + (ArgSize<Args> + ... + 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| struct UNREALSHARPBINDS_API FCSExportedFunction | ||||
| { | ||||
| 	FName Name; | ||||
| 	void* FunctionPointer; | ||||
| 	int32 Size; | ||||
|  | ||||
| 	FCSExportedFunction(const FName& OuterName, const FName& Name, void* InFunctionPointer, int32 InSize); | ||||
| }; | ||||
| @ -0,0 +1,16 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "Modules/ModuleManager.h" | ||||
|  | ||||
| DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpBinds, Log, All); | ||||
|  | ||||
| class FUnrealSharpBindsModule : public IModuleInterface | ||||
| { | ||||
| public: | ||||
|      | ||||
|     // IModuleInterface interface | ||||
|     virtual void StartupModule() override; | ||||
|     virtual void ShutdownModule() override; | ||||
|     // End of IModuleInterface interface | ||||
| }; | ||||
| @ -0,0 +1,26 @@ | ||||
| using UnrealBuildTool; | ||||
|  | ||||
| public class UnrealSharpBinds : ModuleRules | ||||
| { | ||||
|     public UnrealSharpBinds(ReadOnlyTargetRules Target) : base(Target) | ||||
|     { | ||||
|         PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | ||||
|  | ||||
|         PublicDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "Core", | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         PrivateDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "CoreUObject", | ||||
|                 "Engine", | ||||
|                 "Slate", | ||||
|                 "SlateCore" | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,124 @@ | ||||
| #include "K2Node_CSAsyncAction.h" | ||||
|  | ||||
| #include "BlueprintActionDatabaseRegistrar.h" | ||||
| #include "BlueprintFunctionNodeSpawner.h" | ||||
| #include "BlueprintNodeSpawner.h" | ||||
| #include "Delegates/Delegate.h" | ||||
| #include "EdGraph/EdGraphNode.h" | ||||
| #include "Extensions/BlueprintActions/CSBlueprintAsyncActionBase.h" | ||||
| #include "HAL/Platform.h" | ||||
| #include "Misc/AssertionMacros.h" | ||||
| #include "Templates/Casts.h" | ||||
| #include "Templates/SubclassOf.h" | ||||
| #include "TypeGenerator/CSClass.h" | ||||
| #include "UObject/Class.h" | ||||
| #include "UObject/Field.h" | ||||
| #include "UObject/NameTypes.h" | ||||
| #include "UObject/ObjectPtr.h" | ||||
| #include "UObject/UnrealType.h" | ||||
| #include "UObject/WeakObjectPtrTemplates.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "K2Node" | ||||
|  | ||||
| UK2Node_CSAsyncAction::UK2Node_CSAsyncAction() | ||||
| { | ||||
| 	ProxyActivateFunctionName = GET_FUNCTION_NAME_CHECKED(UCSBlueprintAsyncActionBase, Activate); | ||||
| } | ||||
|  | ||||
| void UK2Node_CSAsyncAction::SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr) | ||||
| { | ||||
| 	UK2Node_CSAsyncAction* AsyncTaskNode = CastChecked<UK2Node_CSAsyncAction>(NewNode); | ||||
| 	if (FunctionPtr.IsValid()) | ||||
| 	{ | ||||
| 		UFunction* Func = FunctionPtr.Get(); | ||||
| 		FObjectProperty* ReturnProp = CastFieldChecked<FObjectProperty>(Func->GetReturnProperty()); | ||||
| 						 | ||||
| 		AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName(); | ||||
| 		AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass(); | ||||
| 		AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UK2Node_CSAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const | ||||
| { | ||||
| 	struct GetMenuActions_Utils | ||||
| 	{ | ||||
| 		static bool IsFactoryMethod(const UFunction* Function, const UClass* InTargetType) | ||||
| 		{ | ||||
| 			if (!Function->HasAnyFunctionFlags(FUNC_Static)) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			if (!Function->GetOwnerClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists)) | ||||
| 			{ | ||||
| 				FObjectProperty* ReturnProperty = CastField<FObjectProperty>(Function->GetReturnProperty()); | ||||
| 				// see if the function is a static factory method | ||||
| 				bool const bIsFactoryMethod = (ReturnProperty != nullptr) && (ReturnProperty->PropertyClass != nullptr) && | ||||
| 					ReturnProperty->PropertyClass->IsChildOf(InTargetType); | ||||
|  | ||||
| 				return bIsFactoryMethod; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		static UBlueprintNodeSpawner* MakeAction(UClass* NodeClass, const UFunction* FactoryFunc) | ||||
| 		{ | ||||
| 			UClass* FactoryClass = FactoryFunc ? FactoryFunc->GetOwnerClass() : nullptr; | ||||
| 			if (FactoryClass && FactoryClass->HasMetaData(TEXT("HasDedicatedAsyncNode"))) | ||||
| 			{ | ||||
| 				// Wants to use a more specific blueprint node to handle the async action | ||||
| 				return nullptr; | ||||
| 			} | ||||
|  | ||||
| 			UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc); | ||||
| 			check(NodeSpawner != nullptr); | ||||
| 			NodeSpawner->NodeClass = NodeClass; | ||||
|  | ||||
| 			TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc)); | ||||
| 			NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(SetNodeFunc, FunctionPtr); | ||||
|  | ||||
| 			return NodeSpawner; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	UClass* NodeClass = GetClass(); | ||||
| 	UClass* TargetType = UCSBlueprintAsyncActionBase::StaticClass(); | ||||
|  | ||||
| 	for (TObjectIterator<UCSClass> ClassIt; ClassIt; ++ClassIt) | ||||
| 	{ | ||||
| 		UCSClass* Class = *ClassIt; | ||||
| 		if (Class->HasAnyClassFlags(CLASS_Abstract) || !Class->IsChildOf(TargetType)) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt) | ||||
| 		{ | ||||
| 			UFunction* Function = *FuncIt; | ||||
| 			if (!GetMenuActions_Utils::IsFactoryMethod(Function, TargetType)) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if (UBlueprintNodeSpawner* NewAction = GetMenuActions_Utils::MakeAction(NodeClass, Function)) | ||||
| 			{ | ||||
| 				ActionRegistrar.AddBlueprintAction(Class, NewAction); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UK2Node_CSAsyncAction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) | ||||
| { | ||||
| 	if (ProxyClass->bLayoutChanging) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	Super::ExpandNode(CompilerContext, SourceGraph); | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
| @ -0,0 +1,30 @@ | ||||
| // Copyright Epic Games, Inc. All Rights Reserved. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "K2Node_BaseAsyncTask.h" | ||||
| #include "UObject/ObjectMacros.h" | ||||
| #include "UObject/UObjectGlobals.h" | ||||
|  | ||||
| #include "K2Node_CSAsyncAction.generated.h" | ||||
|  | ||||
| class FBlueprintActionDatabaseRegistrar; | ||||
| class UObject; | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPBLUEPRINT_API UK2Node_CSAsyncAction : public UK2Node_BaseAsyncTask | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UK2Node_CSAsyncAction(); | ||||
|  | ||||
| 	static void SetNodeFunc(UEdGraphNode* NewNode, bool, TWeakObjectPtr<UFunction> FunctionPtr); | ||||
|  | ||||
| 	// UK2Node interface | ||||
| 	virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; | ||||
| 	virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override; | ||||
| 	// End of UK2Node interface | ||||
| }; | ||||
| @ -0,0 +1,124 @@ | ||||
| #include "K2Node_CSCancellableAsyncAction.h" | ||||
|  | ||||
| #include "BlueprintActionDatabaseRegistrar.h" | ||||
| #include "BlueprintFunctionNodeSpawner.h" | ||||
| #include "BlueprintNodeSpawner.h" | ||||
| #include "Delegates/Delegate.h" | ||||
| #include "EdGraph/EdGraphNode.h" | ||||
| #include "Extensions/BlueprintActions/CSCancellableAsyncAction.h" | ||||
| #include "HAL/Platform.h" | ||||
| #include "Misc/AssertionMacros.h" | ||||
| #include "Templates/Casts.h" | ||||
| #include "Templates/SubclassOf.h" | ||||
| #include "TypeGenerator/CSClass.h" | ||||
| #include "UObject/Class.h" | ||||
| #include "UObject/Field.h" | ||||
| #include "UObject/NameTypes.h" | ||||
| #include "UObject/ObjectPtr.h" | ||||
| #include "UObject/UnrealType.h" | ||||
| #include "UObject/WeakObjectPtrTemplates.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "K2Node" | ||||
|  | ||||
| UK2Node_CSCancellableAsyncAction::UK2Node_CSCancellableAsyncAction() | ||||
| { | ||||
| 	ProxyActivateFunctionName = GET_FUNCTION_NAME_CHECKED(UCSCancellableAsyncAction, Activate); | ||||
| } | ||||
|  | ||||
| void UK2Node_CSCancellableAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const | ||||
| { | ||||
| 	struct GetMenuActions_Utils | ||||
| 	{ | ||||
| 		static bool IsFactoryMethod(const UFunction* Function, const UClass* InTargetType) | ||||
| 		{ | ||||
| 			if (!Function->HasAnyFunctionFlags(FUNC_Static)) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			if (!Function->GetOwnerClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists)) | ||||
| 			{ | ||||
| 				FObjectProperty* ReturnProperty = CastField<FObjectProperty>(Function->GetReturnProperty()); | ||||
| 				// see if the function is a static factory method | ||||
| 				bool const bIsFactoryMethod = (ReturnProperty != nullptr) && (ReturnProperty->PropertyClass != nullptr) && | ||||
| 					ReturnProperty->PropertyClass->IsChildOf(InTargetType); | ||||
|  | ||||
| 				return bIsFactoryMethod; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		static void SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr) | ||||
| 		{ | ||||
| 			UK2Node_CSCancellableAsyncAction* AsyncTaskNode = CastChecked<UK2Node_CSCancellableAsyncAction>(NewNode); | ||||
| 			if (FunctionPtr.IsValid()) | ||||
| 			{ | ||||
| 				UFunction* Func = FunctionPtr.Get(); | ||||
| 				FObjectProperty* ReturnProp = CastFieldChecked<FObjectProperty>(Func->GetReturnProperty()); | ||||
| 						 | ||||
| 				AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName(); | ||||
| 				AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass(); | ||||
| 				AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		static UBlueprintNodeSpawner* MakeAction(UClass* NodeClass, const UFunction* FactoryFunc) | ||||
| 		{ | ||||
| 			UClass* FactoryClass = FactoryFunc ? FactoryFunc->GetOwnerClass() : nullptr; | ||||
| 			if (FactoryClass && FactoryClass->HasMetaData(TEXT("HasDedicatedAsyncNode"))) | ||||
| 			{ | ||||
| 				// Wants to use a more specific blueprint node to handle the async action | ||||
| 				return nullptr; | ||||
| 			} | ||||
|  | ||||
| 			UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc); | ||||
| 			check(NodeSpawner != nullptr); | ||||
| 			NodeSpawner->NodeClass = NodeClass; | ||||
|  | ||||
| 			TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc)); | ||||
| 			NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(GetMenuActions_Utils::SetNodeFunc, FunctionPtr); | ||||
|  | ||||
| 			return NodeSpawner; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	UClass* NodeClass = GetClass(); | ||||
| 	UClass* TargetType = UCSCancellableAsyncAction::StaticClass(); | ||||
|  | ||||
| 	for (TObjectIterator<UCSClass> ClassIt; ClassIt; ++ClassIt) | ||||
| 	{ | ||||
| 		UCSClass* Class = *ClassIt; | ||||
| 		if (Class->HasAnyClassFlags(CLASS_Abstract) || !Class->IsChildOf(TargetType)) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt) | ||||
| 		{ | ||||
| 			UFunction* Function = *FuncIt; | ||||
| 			if (!GetMenuActions_Utils::IsFactoryMethod(Function, TargetType)) | ||||
| 			{ | ||||
| 				continue; | ||||
| 			} | ||||
| 			else if (UBlueprintNodeSpawner* NewAction = GetMenuActions_Utils::MakeAction(NodeClass, Function)) | ||||
| 			{ | ||||
| 				ActionRegistrar.AddBlueprintAction(Class, NewAction); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UK2Node_CSCancellableAsyncAction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) | ||||
| { | ||||
| 	if (ProxyClass->bLayoutChanging) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	Super::ExpandNode(CompilerContext, SourceGraph); | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
| @ -0,0 +1,28 @@ | ||||
| // Copyright Epic Games, Inc. All Rights Reserved. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "K2Node_CSAsyncAction.h" | ||||
| #include "UObject/ObjectMacros.h" | ||||
| #include "UObject/UObjectGlobals.h" | ||||
|  | ||||
| #include "K2Node_CSCancellableAsyncAction.generated.h" | ||||
|  | ||||
| class FBlueprintActionDatabaseRegistrar; | ||||
| class UObject; | ||||
|  | ||||
| UCLASS() | ||||
| class UK2Node_CSCancellableAsyncAction : public UK2Node_CSAsyncAction | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UK2Node_CSCancellableAsyncAction(); | ||||
| 	 | ||||
| 	// UK2Node interface | ||||
| 	virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override; | ||||
| 	virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override; | ||||
| 	// End of UK2Node interface | ||||
| }; | ||||
| @ -0,0 +1,28 @@ | ||||
| using UnrealBuildTool; | ||||
|  | ||||
| public class UnrealSharpBlueprint : ModuleRules | ||||
| { | ||||
|     public UnrealSharpBlueprint(ReadOnlyTargetRules Target) : base(Target) | ||||
|     { | ||||
|         PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | ||||
|  | ||||
|         PublicDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "Core", | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         PrivateDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "CoreUObject", | ||||
|                 "Engine", | ||||
|                 "UnrealSharpCore", | ||||
|                 "BlueprintGraph" | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         PublicDefinitions.Add("SkipGlueGeneration"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| #include "UnrealSharpBlueprint.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "FUnrealSharpBlueprintModule" | ||||
|  | ||||
| void FUnrealSharpBlueprintModule::StartupModule() | ||||
| { | ||||
| 	 | ||||
| } | ||||
|  | ||||
| void FUnrealSharpBlueprintModule::ShutdownModule() | ||||
| { | ||||
| 	 | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
|      | ||||
| IMPLEMENT_MODULE(FUnrealSharpBlueprintModule, UnrealSharpBlueprint) | ||||
| @ -0,0 +1,14 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "Modules/ModuleManager.h" | ||||
|  | ||||
| class FUnrealSharpBlueprintModule : public IModuleInterface | ||||
| { | ||||
| public: | ||||
|  | ||||
|     // IModuleInterface interface begin | ||||
|     virtual void StartupModule() override; | ||||
|     virtual void ShutdownModule() override; | ||||
|     // End | ||||
| }; | ||||
| @ -0,0 +1,17 @@ | ||||
| #include "CSBlueprintCompiler.h" | ||||
| #include "CSCompilerContext.h" | ||||
| #include "TypeGenerator/CSBlueprint.h" | ||||
|  | ||||
| bool FCSBlueprintCompiler::CanCompile(const UBlueprint* Blueprint) | ||||
| { | ||||
| 	return Blueprint->IsA<UCSBlueprint>(); | ||||
| } | ||||
|  | ||||
| void FCSBlueprintCompiler::Compile(UBlueprint* Blueprint, const FKismetCompilerOptions& CompileOptions, FCompilerResultsLog& Results) | ||||
| { | ||||
| 	if (UCSBlueprint* CSBlueprint = CastChecked<UCSBlueprint>(Blueprint)) | ||||
| 	{ | ||||
| 		FCSCompilerContext Compiler(CSBlueprint, Results, CompileOptions); | ||||
| 		Compiler.Compile(); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,16 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "KismetCompilerModule.h" | ||||
|  | ||||
| class UCSClass; | ||||
| class UCSBlueprint; | ||||
|  | ||||
| class FCSBlueprintCompiler : public IBlueprintCompiler | ||||
| { | ||||
| public: | ||||
| 	// IBlueprintCompiler interface | ||||
| 	virtual bool CanCompile(const UBlueprint* Blueprint) override; | ||||
| 	virtual void Compile(UBlueprint* Blueprint, const FKismetCompilerOptions& CompileOptions, FCompilerResultsLog& Results) override; | ||||
| 	// End of IBlueprintCompiler interface | ||||
| }; | ||||
| @ -0,0 +1,289 @@ | ||||
| #include "CSCompilerContext.h" | ||||
|  | ||||
| #include "BlueprintActionDatabase.h" | ||||
| #include "ISettingsModule.h" | ||||
| #include "BehaviorTree/Tasks/BTTask_BlueprintBase.h" | ||||
| #include "Blueprint/StateTreeTaskBlueprintBase.h" | ||||
| #include "Engine/SCS_Node.h" | ||||
| #include "Engine/SimpleConstructionScript.h" | ||||
| #include "TypeGenerator/CSBlueprint.h" | ||||
| #include "TypeGenerator/CSClass.h" | ||||
| #include "TypeGenerator/CSSkeletonClass.h" | ||||
| #include "TypeGenerator/Factories/CSFunctionFactory.h" | ||||
| #include "TypeGenerator/Factories/CSPropertyFactory.h" | ||||
| #include "TypeGenerator/Factories/PropertyGenerators/CSPropertyGenerator.h" | ||||
| #include "TypeGenerator/Register/CSGeneratedClassBuilder.h" | ||||
| #include "TypeGenerator/Register/CSMetaDataUtils.h" | ||||
| #include "TypeGenerator/Register/CSSimpleConstructionScriptBuilder.h" | ||||
| #include "TypeGenerator/Register/MetaData/CSClassMetaData.h" | ||||
| #include "TypeGenerator/Register/TypeInfo/CSClassInfo.h" | ||||
| #include "UnrealSharpEditor/CSUnrealSharpEditorSettings.h" | ||||
| #include "UnrealSharpUtilities/UnrealSharpUtils.h" | ||||
| #include "Utils/CSClassUtilities.h" | ||||
|  | ||||
| FCSCompilerContext::FCSCompilerContext(UCSBlueprint* Blueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompilerOptions): | ||||
| 	FKismetCompilerContext(Blueprint, InMessageLog, InCompilerOptions) | ||||
| { | ||||
| 	 | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::FinishCompilingClass(UClass* Class) | ||||
| { | ||||
| 	bool bIsSkeletonClass = FCSClassUtilities::IsSkeletonType(Class); | ||||
| 	 | ||||
| 	if (!bIsSkeletonClass) | ||||
| 	{ | ||||
| 		// The skeleton class shouldn't be using the managed constructor since it's not tied to an assembly | ||||
| 		Class->ClassConstructor = &UCSGeneratedClassBuilder::ManagedObjectConstructor; | ||||
| 	} | ||||
|  | ||||
| 	Super::FinishCompilingClass(Class); | ||||
|  | ||||
| 	TSharedPtr<FCSClassMetaData> TypeMetaData = GetClassInfo()->GetTypeMetaData<FCSClassMetaData>(); | ||||
|  | ||||
| 	// Super call overrides the class flags, so we need to set after that | ||||
| 	Class->ClassFlags |= TypeMetaData->ClassFlags; | ||||
| 	 | ||||
| 	if (NeedsToFakeNativeClass(Class) && !bIsSkeletonClass) | ||||
| 	{ | ||||
| 		// There are systems in Unreal (BehaviorTree, StateTree) which uses the AssetRegistry to find BP classes, since our C# classes are not assets, | ||||
| 		// we need to fake that they're native classes in editor in order to be able to find them.  | ||||
|  | ||||
| 		// The functions that are used to find classes are: | ||||
| 		// FGraphNodeClassHelper::BuildClassGraph() | ||||
| 		// FStateTreeNodeClassCache::CacheClasses() | ||||
| 		Class->ClassFlags |= CLASS_Native; | ||||
| 	} | ||||
| 	 | ||||
| 	UCSGeneratedClassBuilder::SetConfigName(Class, TypeMetaData); | ||||
| 	TryInitializeAsDeveloperSettings(Class); | ||||
| 	ApplyMetaData(); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::OnPostCDOCompiled(const UObject::FPostCDOCompiledContext& Context) | ||||
| { | ||||
| 	FKismetCompilerContext::OnPostCDOCompiled(Context); | ||||
| 	 | ||||
| 	UCSGeneratedClassBuilder::SetupDefaultTickSettings(NewClass->GetDefaultObject(), NewClass); | ||||
| 	 | ||||
| 	UCSClass* Class = GetMainClass(); | ||||
| 	if (Class == NewClass) | ||||
| 	{ | ||||
| 		UCSGeneratedClassBuilder::TryRegisterDynamicSubsystem(Class); | ||||
| 		 | ||||
| 		if (GEditor) | ||||
| 		{ | ||||
| 			FBlueprintActionDatabase::Get().RefreshClassActions(Class); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::CreateClassVariablesFromBlueprint() | ||||
| { | ||||
| 	TSharedPtr<FCSClassInfo> ClassInfo = GetMainClass()->GetManagedTypeInfo<FCSClassInfo>(); | ||||
| 	const TArray<FCSPropertyMetaData>& Properties = ClassInfo->GetTypeMetaData<FCSClassMetaData>()->Properties; | ||||
|  | ||||
| 	NewClass->PropertyGuids.Empty(Properties.Num()); | ||||
| 	TryValidateSimpleConstructionScript(ClassInfo); | ||||
| 	 | ||||
| 	FCSPropertyFactory::CreateAndAssignProperties(NewClass, Properties, [this](const FProperty* NewProperty) | ||||
| 	{ | ||||
| 		FName PropertyName = NewProperty->GetFName(); | ||||
| 		FGuid PropertyGuid = FCSUnrealSharpUtils::ConstructGUIDFromName(PropertyName); | ||||
| 		NewClass->PropertyGuids.Add(PropertyName, PropertyGuid); | ||||
| 	}); | ||||
|  | ||||
| 	// Create dummy variables for the blueprint. | ||||
| 	// They should not get compiled, just there for metadata for different Unreal modules. | ||||
| 	CreateDummyBlueprintVariables(Properties); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::CleanAndSanitizeClass(UBlueprintGeneratedClass* ClassToClean, UObject*& InOldCDO) | ||||
| { | ||||
| 	FKismetCompilerContext::CleanAndSanitizeClass(ClassToClean, InOldCDO); | ||||
| 	NewClass->FieldNotifies.Reset(); | ||||
| 	 | ||||
| 	TryDeinitializeAsDeveloperSettings(InOldCDO); | ||||
|  | ||||
| 	// Too late to generate functions in CreateFunctionList for child blueprints | ||||
| 	GenerateFunctions(); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::SpawnNewClass(const FString& NewClassName) | ||||
| { | ||||
| 	UCSClass* MainClass = GetMainClass(); | ||||
| 	UCSSkeletonClass* NewSkeletonClass = NewObject<UCSSkeletonClass>(Blueprint->GetOutermost(), FName(*NewClassName), RF_Public | RF_Transactional); | ||||
| 	NewSkeletonClass->SetGeneratedClass(MainClass); | ||||
| 	NewClass = NewSkeletonClass; | ||||
| 	 | ||||
| 	// Skeleton class doesn't generate functions on the first pass. | ||||
| 	// It's done in CleanAndSanitizeClass which doesn't run when the skeleton class is created | ||||
| 	GenerateFunctions(); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::AddInterfacesFromBlueprint(UClass* Class) | ||||
| { | ||||
| 	UCSGeneratedClassBuilder::ImplementInterfaces(Class, GetTypeMetaData()->Interfaces); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::TryValidateSimpleConstructionScript(const TSharedPtr<const FCSClassInfo>& ClassInfo) const | ||||
| { | ||||
| 	const TArray<FCSPropertyMetaData>& Properties = GetTypeMetaData()->Properties; | ||||
| 	FCSSimpleConstructionScriptBuilder::BuildSimpleConstructionScript(Blueprint->GeneratedClass, &Blueprint->SimpleConstructionScript, Properties); | ||||
| 	 | ||||
| 	if (!Blueprint->SimpleConstructionScript) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	TArray<USCS_Node*> Nodes; | ||||
| 	for (const FCSPropertyMetaData& Property : Properties) | ||||
| 	{ | ||||
| 		if (Property.Type->PropertyType != ECSPropertyType::DefaultComponent) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 		 | ||||
| 		USimpleConstructionScript* SCS = Blueprint->SimpleConstructionScript; | ||||
| 		USCS_Node* Node = SCS->FindSCSNode(Property.Name); | ||||
| 		Nodes.Add(Node); | ||||
| 	} | ||||
|  | ||||
| 	// Remove all nodes that are not part of the class anymore. | ||||
| 	int32 NumNodes = Blueprint->SimpleConstructionScript->GetAllNodes().Num(); | ||||
| 	TArray<USCS_Node*> AllNodes = Blueprint->SimpleConstructionScript->GetAllNodes(); | ||||
| 	for (int32 i = NumNodes - 1; i >= 0; --i) | ||||
| 	{ | ||||
| 		USCS_Node* Node = AllNodes[i]; | ||||
| 		if (!Nodes.Contains(Node)) | ||||
| 		{ | ||||
| 			Blueprint->SimpleConstructionScript->RemoveNode(Node); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	Blueprint->SimpleConstructionScript->ValidateNodeTemplates(MessageLog); | ||||
| 	Blueprint->SimpleConstructionScript->ValidateNodeVariableNames(MessageLog); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::GenerateFunctions() const | ||||
| { | ||||
| 	TSharedPtr<const FCSClassMetaData> TypeMetaData = GetTypeMetaData(); | ||||
|  | ||||
| 	if (TypeMetaData->VirtualFunctions.IsEmpty() && TypeMetaData->Functions.IsEmpty()) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	FCSFunctionFactory::GenerateVirtualFunctions(NewClass, TypeMetaData); | ||||
| 	FCSFunctionFactory::GenerateFunctions(NewClass, TypeMetaData->Functions); | ||||
| } | ||||
|  | ||||
| UCSClass* FCSCompilerContext::GetMainClass() const | ||||
| { | ||||
| 	return CastChecked<UCSClass>(Blueprint->GeneratedClass); | ||||
| } | ||||
|  | ||||
| TSharedPtr<const FCSClassInfo> FCSCompilerContext::GetClassInfo() const | ||||
| { | ||||
| 	return GetMainClass()->GetManagedTypeInfo<FCSClassInfo>(); | ||||
| } | ||||
|  | ||||
| TSharedPtr<const FCSClassMetaData> FCSCompilerContext::GetTypeMetaData() const | ||||
| { | ||||
| 	return GetClassInfo()->GetTypeMetaData<FCSClassMetaData>(); | ||||
| } | ||||
|  | ||||
| bool FCSCompilerContext::IsDeveloperSettings() const | ||||
| { | ||||
| 	return Blueprint->GeneratedClass == NewClass && NewClass->IsChildOf<UDeveloperSettings>(); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::TryInitializeAsDeveloperSettings(const UClass* Class) const | ||||
| { | ||||
| 	if (!IsDeveloperSettings()) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	UDeveloperSettings* Settings = static_cast<UDeveloperSettings*>(Class->GetDefaultObject()); | ||||
| 	ISettingsModule& SettingsModule = FModuleManager::GetModuleChecked<ISettingsModule>("Settings"); | ||||
| 		 | ||||
| 	SettingsModule.RegisterSettings(Settings->GetContainerName(), Settings->GetCategoryName(), Settings->GetSectionName(), | ||||
| 		Settings->GetSectionText(), | ||||
| 		Settings->GetSectionDescription(), | ||||
| 		Settings); | ||||
|  | ||||
| 	Settings->LoadConfig(); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::TryDeinitializeAsDeveloperSettings(UObject* Settings) const | ||||
| { | ||||
| 	if (!IsValid(Settings) || !IsDeveloperSettings()) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	ISettingsModule& SettingsModule = FModuleManager::GetModuleChecked<ISettingsModule>("Settings"); | ||||
| 	UDeveloperSettings* DeveloperSettings = static_cast<UDeveloperSettings*>(Settings); | ||||
| 	SettingsModule.UnregisterSettings(DeveloperSettings->GetContainerName(), DeveloperSettings->GetCategoryName(), DeveloperSettings->GetSectionName()); | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::ApplyMetaData() | ||||
| { | ||||
| 	TSharedPtr<const FCSClassMetaData> TypeMetaData = GetTypeMetaData(); | ||||
| 		 | ||||
| 	static FString DisplayNameKey = TEXT("DisplayName"); | ||||
| 	if (!NewClass->HasMetaData(*DisplayNameKey)) | ||||
| 	{ | ||||
| 		NewClass->SetMetaData(*DisplayNameKey, *Blueprint->GetName()); | ||||
| 	} | ||||
| 		 | ||||
| 	if (GetDefault<UCSUnrealSharpEditorSettings>()->bSuffixGeneratedTypes) | ||||
| 	{ | ||||
| 		FString DisplayName = NewClass->GetMetaData(*DisplayNameKey); | ||||
| 		DisplayName += TEXT(" (C#)"); | ||||
| 		NewClass->SetMetaData(*DisplayNameKey, *DisplayName); | ||||
| 	} | ||||
|  | ||||
| 	FCSMetaDataUtils::ApplyMetaData(TypeMetaData->MetaData, NewClass); | ||||
| } | ||||
|  | ||||
| bool FCSCompilerContext::NeedsToFakeNativeClass(UClass* Class) | ||||
| { | ||||
| 	static TArray ParentClasses = | ||||
| 	{ | ||||
| 		UBTTask_BlueprintBase::StaticClass(), | ||||
| 		UStateTreeTaskBlueprintBase::StaticClass(), | ||||
| 	}; | ||||
|  | ||||
| 	for (UClass* ParentClass  : ParentClasses) | ||||
| 	{ | ||||
| 		if (Class->IsChildOf(ParentClass)) | ||||
| 		{ | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void FCSCompilerContext::CreateDummyBlueprintVariables(const TArray<FCSPropertyMetaData>& Properties) const | ||||
| { | ||||
| 	Blueprint->NewVariables.Empty(Properties.Num()); | ||||
|  | ||||
| 	for (const FCSPropertyMetaData& PropertyMetaData : Properties) | ||||
| 	{ | ||||
| 		FBPVariableDescription VariableDescription; | ||||
| 		VariableDescription.FriendlyName = PropertyMetaData.Name.ToString(); | ||||
| 		VariableDescription.VarName = PropertyMetaData.Name; | ||||
|  | ||||
| 		for (const TTuple<FString, FString>& MetaData : PropertyMetaData.MetaData) | ||||
| 		{ | ||||
| 			VariableDescription.SetMetaData(*MetaData.Key, MetaData.Value); | ||||
| 		} | ||||
|  | ||||
| 		Blueprint->NewVariables.Add(VariableDescription); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
| @ -0,0 +1,43 @@ | ||||
| #pragma once | ||||
| #include "KismetCompiler.h" | ||||
|  | ||||
| struct FCSClassMetaData; | ||||
| struct FCSPropertyMetaData; | ||||
| struct FCSClassInfo; | ||||
| class UCSClass; | ||||
| class UCSBlueprint; | ||||
|  | ||||
| class FCSCompilerContext : public FKismetCompilerContext | ||||
| { | ||||
| public: | ||||
|  | ||||
| 	FCSCompilerContext(UCSBlueprint* Blueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompilerOptions); | ||||
|  | ||||
| 	// FKismetCompilerContext interface | ||||
| 	virtual void FinishCompilingClass(UClass* Class) override; | ||||
| 	virtual void OnPostCDOCompiled(const UObject::FPostCDOCompiledContext& Context) override; | ||||
| 	virtual void CreateClassVariablesFromBlueprint() override; | ||||
| 	virtual void CleanAndSanitizeClass(UBlueprintGeneratedClass* ClassToClean, UObject*& OldCDO) override; | ||||
| 	virtual void SpawnNewClass(const FString& NewClassName) override; | ||||
| 	virtual void AddInterfacesFromBlueprint(UClass* Class) override; | ||||
| 	// End of FKismetCompilerContext interface | ||||
| protected: | ||||
| 	typedef FKismetCompilerContext Super; | ||||
| private: | ||||
| 	void TryValidateSimpleConstructionScript(const TSharedPtr<const FCSClassInfo>& ClassInfo) const; | ||||
| 	void GenerateFunctions() const; | ||||
| 	UCSClass* GetMainClass() const; | ||||
| 	 | ||||
| 	TSharedPtr<const FCSClassInfo> GetClassInfo() const; | ||||
| 	TSharedPtr<const FCSClassMetaData> GetTypeMetaData() const; | ||||
|  | ||||
| 	bool IsDeveloperSettings() const; | ||||
| 	void TryInitializeAsDeveloperSettings(const UClass* Class) const; | ||||
| 	void TryDeinitializeAsDeveloperSettings(UObject* Settings) const; | ||||
| 	void ApplyMetaData(); | ||||
|  | ||||
| 	static bool NeedsToFakeNativeClass(UClass* Class); | ||||
|  | ||||
| 	void CreateDummyBlueprintVariables(const TArray<FCSPropertyMetaData>& Properties) const; | ||||
| }; | ||||
|  | ||||
| @ -0,0 +1,36 @@ | ||||
| using UnrealBuildTool; | ||||
|  | ||||
| public class UnrealSharpCompiler : ModuleRules | ||||
| { | ||||
|     public UnrealSharpCompiler(ReadOnlyTargetRules Target) : base(Target) | ||||
|     { | ||||
|         PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; | ||||
|  | ||||
|         PublicDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "Core", | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         PrivateDependencyModuleNames.AddRange( | ||||
|             new string[] | ||||
|             { | ||||
|                 "CoreUObject", | ||||
|                 "Engine", | ||||
|                 "Slate", | ||||
|                 "SlateCore",  | ||||
|                 "UnrealSharpCore", | ||||
|                 "KismetCompiler", | ||||
|                 "Kismet", | ||||
|                 "BlueprintGraph", | ||||
|                 "UnrealEd", | ||||
|                 "DeveloperSettings",  | ||||
|                 "UnrealSharpEditor",  | ||||
|                 "AIModule",  | ||||
|                 "StateTreeModule",  | ||||
|                 "UnrealSharpUtilities" | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,176 @@ | ||||
| #include "UnrealSharpCompiler.h" | ||||
|  | ||||
| #include "BlueprintActionDatabase.h" | ||||
| #include "BlueprintCompilationManager.h" | ||||
| #include "CSBlueprintCompiler.h" | ||||
| #include "CSCompilerContext.h" | ||||
| #include "CSManager.h" | ||||
| #include "KismetCompiler.h" | ||||
| #include "TypeGenerator/CSBlueprint.h" | ||||
| #include "TypeGenerator/CSClass.h" | ||||
| #include "TypeGenerator/CSEnum.h" | ||||
| #include "TypeGenerator/CSInterface.h" | ||||
| #include "TypeGenerator/CSScriptStruct.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "FUnrealSharpCompilerModule" | ||||
|  | ||||
| DEFINE_LOG_CATEGORY(LogUnrealSharpCompiler); | ||||
|  | ||||
| void FUnrealSharpCompilerModule::StartupModule() | ||||
| { | ||||
| 	UCSManager& CSManager = UCSManager::GetOrCreate(); | ||||
| 	 | ||||
| 	FKismetCompilerContext::RegisterCompilerForBP(UCSBlueprint::StaticClass(), [](UBlueprint* InBlueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions) | ||||
| 	{ | ||||
| 		return MakeShared<FCSCompilerContext>(CastChecked<UCSBlueprint>(InBlueprint), InMessageLog, InCompileOptions); | ||||
| 	}); | ||||
| 	 | ||||
| 	IKismetCompilerInterface& KismetCompilerModule = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler"); | ||||
| 	KismetCompilerModule.GetCompilers().Add(&BlueprintCompiler); | ||||
| 	 | ||||
| 	CSManager.OnNewClassEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewClass); | ||||
| 	CSManager.OnNewEnumEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewEnum); | ||||
| 	CSManager.OnNewStructEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewStruct); | ||||
| 	CSManager.OnNewInterfaceEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewInterface); | ||||
| 	 | ||||
| 	CSManager.OnProcessedPendingClassesEvent().AddRaw(this, &FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints); | ||||
| 	CSManager.OnManagedAssemblyLoadedEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnManagedAssemblyLoaded); | ||||
|  | ||||
| 	// Try to recompile and reinstance all blueprints when the module is loaded. | ||||
| 	CSManager.ForEachManagedPackage([this](const UPackage* Package) | ||||
| 	{ | ||||
| 		ForEachObjectWithPackage(Package, [this](UObject* Object) | ||||
| 		{ | ||||
| 			if (UBlueprint* Blueprint = Cast<UBlueprint>(Object)) | ||||
| 			{ | ||||
| 				OnNewClass(static_cast<UCSClass*>(Blueprint->GeneratedClass.Get())); | ||||
| 			} | ||||
| 			return true; | ||||
| 		}, false); | ||||
| 	}); | ||||
| 	 | ||||
| 	RecompileAndReinstanceBlueprints(); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::ShutdownModule() | ||||
| { | ||||
|      | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints() | ||||
| { | ||||
| 	if (UCSManager::Get().IsLoadingAnyAssembly()) | ||||
| 	{ | ||||
| 		// Wait until all assemblies are loaded, so we can recompile all blueprints at once. | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	if (ManagedComponentsToCompile.IsEmpty() && ManagedClassesToCompile.IsEmpty()) | ||||
| 	{ | ||||
| 		// Nothing to compile. | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	auto CompileBlueprints = [this](TArray<UBlueprint*>& Blueprints) | ||||
| 	{ | ||||
| 		if (Blueprints.IsEmpty()) | ||||
| 		{ | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		for (int32 i = 0; i < Blueprints.Num(); ++i) | ||||
| 		{ | ||||
| 			UBlueprint* Blueprint = Blueprints[i]; | ||||
|  | ||||
| 			if (!Blueprint) | ||||
| 			{ | ||||
| 				UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint is null, skipping compilation."); | ||||
| 				continue; | ||||
| 			} | ||||
| 			 | ||||
| 			if (!IsValid(Blueprint)) | ||||
| 			{ | ||||
| 				UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint {0} is garbage, skipping compilation.", *Blueprint->GetName()); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::SkipGarbageCollection); | ||||
| 		} | ||||
| 		 | ||||
| 		Blueprints.Reset(); | ||||
| 	}; | ||||
|  | ||||
| 	// Components needs be compiled first, as they are instantiated by the owning actor, and needs their size to be known. | ||||
| 	CompileBlueprints(ManagedComponentsToCompile); | ||||
| 	CompileBlueprints(ManagedClassesToCompile); | ||||
|  | ||||
| 	CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::AddManagedReferences(FCSManagedReferencesCollection& Collection) | ||||
| { | ||||
| 	Collection.ForEachManagedReference([&](UStruct* Struct) | ||||
| 	{ | ||||
| 		if (UCSClass* Class = Cast<UCSClass>(Struct)) | ||||
| 		{ | ||||
| 			OnNewClass(Class); | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::OnNewClass(UCSClass* NewClass) | ||||
| { | ||||
| 	UBlueprint* Blueprint = Cast<UBlueprint>(NewClass->ClassGeneratedBy); | ||||
| 	if (!IsValid(Blueprint)) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	auto AddToCompileList = [this](TArray<UBlueprint*>& List, UBlueprint* Blueprint) | ||||
| 	{ | ||||
| 		if (List.Contains(Blueprint)) | ||||
| 		{ | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		List.Add(Blueprint); | ||||
| 	}; | ||||
| 		 | ||||
| 	if (NewClass->IsChildOf(UActorComponent::StaticClass())) | ||||
| 	{ | ||||
| 		AddToCompileList(ManagedComponentsToCompile, Blueprint); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		AddToCompileList(ManagedClassesToCompile, Blueprint); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::OnNewStruct(UCSScriptStruct* NewStruct) | ||||
| { | ||||
| 	AddManagedReferences(NewStruct->ManagedReferences); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::OnNewEnum(UCSEnum* NewEnum) | ||||
| { | ||||
| 	AddManagedReferences(NewEnum->ManagedReferences); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::OnNewInterface(UCSInterface* NewInterface) | ||||
| { | ||||
| 	if (!IsValid(GEditor)) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
| 	 | ||||
| 	FBlueprintActionDatabase::Get().RefreshClassActions(NewInterface); | ||||
| } | ||||
|  | ||||
| void FUnrealSharpCompilerModule::OnManagedAssemblyLoaded(const FName& AssemblyName) | ||||
| { | ||||
| 	RecompileAndReinstanceBlueprints(); | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
|      | ||||
| IMPLEMENT_MODULE(FUnrealSharpCompilerModule, UnrealSharpCompiler) | ||||
| @ -0,0 +1,36 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBlueprintCompiler.h" | ||||
| #include "Modules/ModuleManager.h" | ||||
|  | ||||
| class UCSInterface; | ||||
| struct FCSManagedReferencesCollection; | ||||
| class UCSEnum; | ||||
| class UCSScriptStruct; | ||||
| class FCSBlueprintCompiler; | ||||
|  | ||||
| DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpCompiler, Log, All); | ||||
|  | ||||
| class FUnrealSharpCompilerModule : public IModuleInterface | ||||
| { | ||||
| public: | ||||
|     virtual void StartupModule() override; | ||||
|     virtual void ShutdownModule() override; | ||||
| private: | ||||
|      | ||||
|     void OnNewClass(UCSClass* NewClass); | ||||
|     void OnNewStruct(UCSScriptStruct* NewStruct); | ||||
|     void OnNewEnum(UCSEnum* NewEnum); | ||||
|     void OnNewInterface(UCSInterface* NewInterface); | ||||
|      | ||||
|     void OnManagedAssemblyLoaded(const FName& AssemblyName); | ||||
|     void RecompileAndReinstanceBlueprints(); | ||||
|  | ||||
|     void AddManagedReferences(FCSManagedReferencesCollection& Collection); | ||||
|  | ||||
|     FCSBlueprintCompiler BlueprintCompiler; | ||||
|      | ||||
|     TArray<UBlueprint*> ManagedClassesToCompile; | ||||
|     TArray<UBlueprint*> ManagedComponentsToCompile; | ||||
| }; | ||||
							
								
								
									
										381
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,381 @@ | ||||
| #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 | ||||
| } | ||||
							
								
								
									
										173
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | ||||
| #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; | ||||
| }; | ||||
							
								
								
									
										14
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #include "CSFieldName.h" | ||||
| #include "UnrealSharpUtilities/UnrealSharpUtils.h" | ||||
| #include "Utils/CSClassUtilities.h" | ||||
|  | ||||
| FCSFieldName::FCSFieldName(UField* Field) | ||||
| { | ||||
| 	if (UClass* Class = Cast<UClass>(Field)) | ||||
| 	{ | ||||
| 		Field = FCSClassUtilities::GetFirstNativeClass(Class); | ||||
| 	} | ||||
| 	 | ||||
| 	Name = Field->GetFName(); | ||||
| 	Namespace = FCSUnrealSharpUtils::GetNamespace(Field); | ||||
| } | ||||
							
								
								
									
										37
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CSNamespace.h" | ||||
|  | ||||
| struct UNREALSHARPCORE_API FCSFieldName | ||||
| { | ||||
| 	FCSFieldName() = default; | ||||
| 	FCSFieldName(FName Name, FName Namespace) : Name(Name), Namespace(Namespace) {} | ||||
| 	FCSFieldName(UField* Field); | ||||
|  | ||||
| 	FName GetFName() const { return Name; } | ||||
| 	FString GetName() const { return Name.ToString(); } | ||||
| 	 | ||||
| 	bool IsValid() const { return Name != NAME_None; } | ||||
| 	 | ||||
| 	FCSNamespace GetNamespace() const { return Namespace; } | ||||
| 	UPackage* GetPackage() const { return Namespace.GetPackage(); } | ||||
| 	FName GetPackageName() const { return Namespace.GetPackageName(); } | ||||
| 	 | ||||
| 	FName GetFullName() const | ||||
| 	{ | ||||
| 		return *FString::Printf(TEXT("%s.%s"), *Namespace.GetName(), *Name.ToString()); | ||||
| 	} | ||||
|  | ||||
| 	bool operator == (const FCSFieldName& Other) const | ||||
| 	{ | ||||
| 		return Name == Other.Name && Namespace == Other.Namespace; | ||||
| 	} | ||||
|  | ||||
| 	friend uint32 GetTypeHash(const FCSFieldName& Field) | ||||
| 	{ | ||||
| 		return GetTypeHash(Field.Name) ^ GetTypeHash(Field.Namespace); | ||||
| 	} | ||||
| private: | ||||
| 	FName Name; | ||||
| 	FCSNamespace Namespace; | ||||
| }; | ||||
| @ -0,0 +1,50 @@ | ||||
| #pragma once | ||||
|  | ||||
| #if !defined(_WIN32) | ||||
| #define __stdcall | ||||
| #endif | ||||
|  | ||||
| struct FScopedGCHandle; | ||||
| struct FInvokeManagedMethodData; | ||||
| struct FGCHandleIntPtr; | ||||
| struct FGCHandle; | ||||
|  | ||||
| class UNREALSHARPCORE_API FCSManagedCallbacks | ||||
| { | ||||
| 	public: | ||||
|  | ||||
| 	struct FManagedCallbacks | ||||
| 	{ | ||||
| 		using ManagedCallbacks_CreateNewManagedObject = FGCHandleIntPtr(__stdcall*)(const void*, void*, TCHAR**); | ||||
| 		using ManagedCallbacks_CreateNewManagedObjectWrapper = FGCHandleIntPtr(__stdcall*)(void*, void*); | ||||
| 		using ManagedCallbacks_InvokeManagedEvent = int(__stdcall*)(void*, void*, void*, void*, void*); | ||||
| 		using ManagedCallbacks_InvokeDelegate = int(__stdcall*)(FGCHandleIntPtr); | ||||
| 		using ManagedCallbacks_LookupMethod = uint8*(__stdcall*)(void*, const TCHAR*); | ||||
| 		using ManagedCallbacks_LookupType = uint8*(__stdcall*)(uint8*, const TCHAR*); | ||||
| 		using ManagedCallbacks_Dispose = void(__stdcall*)(FGCHandleIntPtr, FGCHandleIntPtr); | ||||
| 		using ManagedCallbacks_FreeHandle = void(__stdcall*)(FGCHandleIntPtr); | ||||
| 		 | ||||
| 		ManagedCallbacks_CreateNewManagedObject CreateNewManagedObject; | ||||
| 		ManagedCallbacks_CreateNewManagedObjectWrapper CreateNewManagedObjectWrapper; | ||||
| 		ManagedCallbacks_InvokeManagedEvent InvokeManagedMethod; | ||||
| 		ManagedCallbacks_InvokeDelegate InvokeDelegate; | ||||
| 		ManagedCallbacks_LookupMethod LookupManagedMethod; | ||||
| 		ManagedCallbacks_LookupType LookupManagedType; | ||||
|  | ||||
| 	private: | ||||
| 		//Only call these from GCHandles. | ||||
| 		friend FGCHandle; | ||||
| 	    friend FScopedGCHandle; | ||||
| 		ManagedCallbacks_Dispose Dispose; | ||||
| 		ManagedCallbacks_FreeHandle FreeHandle; | ||||
| 	}; | ||||
| 	 | ||||
| 	static inline FManagedCallbacks ManagedCallbacks; | ||||
| 	 | ||||
| }; | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| @ -0,0 +1,26 @@ | ||||
| #include "CSManagedDelegate.h" | ||||
|  | ||||
| #include "CSManager.h" | ||||
|  | ||||
| void FCSManagedDelegate::Invoke(UObject* WorldContextObject, bool bDispose) | ||||
| { | ||||
| 	TRACE_CPUPROFILER_EVENT_SCOPE(FCSManagedDelegate::Invoke); | ||||
|  | ||||
| 	if (CallbackHandle.IsNull()) | ||||
| 	{ | ||||
| 		UE_LOGFMT(LogUnrealSharp, Warning, "FCSManagedDelegate::Invoke: CallbackHandle is null"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (IsValid(WorldContextObject)) | ||||
| 	{ | ||||
| 		UCSManager::Get().SetCurrentWorldContext(WorldContextObject); | ||||
| 	} | ||||
|  | ||||
| 	FCSManagedCallbacks::ManagedCallbacks.InvokeDelegate(CallbackHandle.GetHandle()); | ||||
|  | ||||
| 	if (bDispose) | ||||
| 	{ | ||||
| 		Dispose(); | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,22 @@ | ||||
| #pragma once | ||||
| #include "CSManagedGCHandle.h" | ||||
|  | ||||
| struct UNREALSHARPCORE_API FCSManagedDelegate | ||||
| { | ||||
| 	FCSManagedDelegate(const FGCHandle& ManagedDelegate) | ||||
| 		: CallbackHandle(ManagedDelegate) | ||||
| 	{ | ||||
| 		 | ||||
| 	} | ||||
|  | ||||
| 	FCSManagedDelegate() | ||||
| 	{ | ||||
| 		 | ||||
| 	} | ||||
| 	 | ||||
| 	void Invoke(UObject* WorldContextObject = nullptr, bool bDispose = true); | ||||
| 	void Dispose() { CallbackHandle.Dispose(); } | ||||
|  | ||||
| private: | ||||
| 	FGCHandle CallbackHandle; | ||||
| }; | ||||
							
								
								
									
										124
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManagedGCHandle.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManagedGCHandle.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,124 @@ | ||||
| #pragma once | ||||
| #include "CSManagedCallbacksCache.h" | ||||
| #include "CSManagedGCHandle.generated.h" | ||||
|  | ||||
| enum class GCHandleType : char | ||||
| { | ||||
| 	Null, | ||||
| 	StrongHandle, | ||||
| 	WeakHandle, | ||||
| 	PinnedHandle, | ||||
| }; | ||||
|  | ||||
| struct FGCHandleIntPtr | ||||
| { | ||||
| 	bool operator == (const FGCHandleIntPtr& Other) const | ||||
| 	{ | ||||
| 		return IntPtr == Other.IntPtr; | ||||
| 	} | ||||
|  | ||||
| 	bool operator != (const FGCHandleIntPtr& Other) const | ||||
| 	{ | ||||
| 		return IntPtr != Other.IntPtr; | ||||
| 	} | ||||
| 	 | ||||
| 	// Pointer to the managed object in C# | ||||
| 	uint8* IntPtr = nullptr; | ||||
| }; | ||||
|  | ||||
| static_assert(sizeof(FGCHandleIntPtr) == sizeof(void *)); | ||||
|  | ||||
| struct FGCHandle | ||||
| { | ||||
| 	FGCHandleIntPtr Handle; | ||||
| 	GCHandleType Type = GCHandleType::Null; | ||||
|  | ||||
| 	static FGCHandle Null() { return FGCHandle(nullptr, GCHandleType::Null); } | ||||
|  | ||||
| 	bool IsNull() const { return !Handle.IntPtr; } | ||||
| 	bool IsWeakPointer() const { return Type == GCHandleType::WeakHandle; } | ||||
| 	 | ||||
| 	FGCHandleIntPtr GetHandle() const { return Handle; } | ||||
| 	uint8* GetPointer() const { return Handle.IntPtr; }; | ||||
| 	 | ||||
| 	void Dispose(FGCHandleIntPtr AssemblyHandle = FGCHandleIntPtr()) | ||||
| 	{ | ||||
| 		if (!Handle.IntPtr || Type == GCHandleType::Null) | ||||
| 		{ | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		FCSManagedCallbacks::ManagedCallbacks.Dispose(Handle, AssemblyHandle); | ||||
| 	 | ||||
| 		Handle.IntPtr = nullptr; | ||||
| 		Type = GCHandleType::Null; | ||||
| 	} | ||||
|  | ||||
| 	void operator = (const FGCHandle& Other) | ||||
| 	{ | ||||
| 		Handle = Other.Handle; | ||||
| 		Type = Other.Type; | ||||
| 	} | ||||
| 	 | ||||
| 	operator void*() const | ||||
| 	{ | ||||
| 		return Handle.IntPtr; | ||||
| 	} | ||||
|  | ||||
| 	FGCHandle(){} | ||||
| 	FGCHandle(const FGCHandleIntPtr InHandle, const GCHandleType InType) : Handle(InHandle), Type(InType) {} | ||||
|  | ||||
| 	FGCHandle(uint8* InHandle, const GCHandleType InType) : Type(InType) | ||||
| 	{ | ||||
| 		Handle.IntPtr = InHandle; | ||||
| 	} | ||||
|  | ||||
| 	FGCHandle(const FGCHandleIntPtr InHandle) : Handle(InHandle) | ||||
| 	{ | ||||
| 		Type = GCHandleType::Null; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| struct FScopedGCHandle | ||||
| { | ||||
|      | ||||
|     FGCHandleIntPtr Handle; | ||||
|  | ||||
|     explicit FScopedGCHandle(FGCHandleIntPtr InHandle) : Handle(InHandle) {} | ||||
|  | ||||
|     FScopedGCHandle(const FScopedGCHandle&) = delete; | ||||
|     FScopedGCHandle(FScopedGCHandle&&) = delete; | ||||
|  | ||||
|     ~FScopedGCHandle() | ||||
|     { | ||||
|         if (Handle.IntPtr != nullptr)  | ||||
|         { | ||||
|             FCSManagedCallbacks::ManagedCallbacks.FreeHandle(Handle); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     FScopedGCHandle& operator=(const FScopedGCHandle&) = delete; | ||||
|     FScopedGCHandle& operator=(FScopedGCHandle&&) = delete; | ||||
| }; | ||||
|  | ||||
| USTRUCT() | ||||
| struct FSharedGCHandle | ||||
| { | ||||
|     GENERATED_BODY() | ||||
|  | ||||
|     FSharedGCHandle() = default; | ||||
|     explicit FSharedGCHandle(FGCHandleIntPtr InHandle) : Handle(MakeShared<FScopedGCHandle>(InHandle)) {} | ||||
|  | ||||
|     FGCHandleIntPtr GetHandle() const | ||||
|     { | ||||
|         if (Handle == nullptr)  | ||||
|         { | ||||
|             return FGCHandleIntPtr(); | ||||
|         } | ||||
|          | ||||
|         return Handle->Handle; | ||||
|     } | ||||
|      | ||||
| private: | ||||
|     TSharedPtr<FScopedGCHandle> Handle; | ||||
| }; | ||||
							
								
								
									
										678
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										678
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,678 @@ | ||||
| #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; | ||||
| } | ||||
							
								
								
									
										208
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <coreclr_delegates.h> | ||||
| #include <hostfxr.h> | ||||
| #include "CSAssembly.h" | ||||
| #include "CSManagedCallbacksCache.h" | ||||
| #include "CSManager.generated.h" | ||||
|  | ||||
| class UCSTypeBuilderManager; | ||||
| class UCSInterface; | ||||
| class UCSEnum; | ||||
| class UCSScriptStruct; | ||||
| class FUnrealSharpCoreModule; | ||||
| class UFunctionsExporter; | ||||
| struct FCSNamespace; | ||||
| struct FCSTypeReferenceMetaData; | ||||
|  | ||||
| struct FCSManagedPluginCallbacks | ||||
| { | ||||
| 	using LoadPluginCallback = FGCHandleIntPtr(__stdcall*)(const TCHAR*, bool); | ||||
| 	using UnloadPluginCallback = bool(__stdcall*)(const TCHAR*); | ||||
|  | ||||
| 	LoadPluginCallback LoadPlugin = nullptr; | ||||
| 	UnloadPluginCallback UnloadPlugin = nullptr; | ||||
| }; | ||||
|  | ||||
| using FInitializeRuntimeHost = bool (*)(const TCHAR*, const TCHAR*, FCSManagedPluginCallbacks*, const void*, FCSManagedCallbacks::FManagedCallbacks*); | ||||
|  | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FOnManagedAssemblyLoaded, const FName&); | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FOnManagedAssemblyUnloaded, const FName&); | ||||
| DECLARE_MULTICAST_DELEGATE(FOnAssembliesReloaded); | ||||
|  | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FCSClassEvent, UCSClass*); | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FCSStructEvent, UCSScriptStruct*); | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FCSInterfaceEvent, UCSInterface*); | ||||
| DECLARE_MULTICAST_DELEGATE_OneParam(FCSEnumEvent, UCSEnum*); | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UCSManager : public UObject, public FUObjectArray::FUObjectDeleteListener | ||||
| { | ||||
|     GENERATED_BODY() | ||||
| public: | ||||
|  | ||||
|     static UCSManager& GetOrCreate() | ||||
|     { | ||||
|         if (!Instance) | ||||
|         { | ||||
|             Instance = NewObject<UCSManager>(GetTransientPackage(), TEXT("CSManager"), RF_Public | RF_MarkAsRootSet); | ||||
|         } | ||||
|  | ||||
|         return *Instance; | ||||
|     } | ||||
|  | ||||
|     static UCSManager& Get() { return *Instance; } | ||||
|  | ||||
|     // The outermost package for all managed packages. If namespace support is off, this is the only package that will be used. | ||||
|     UPackage* GetGlobalManagedPackage() const { return GlobalManagedPackage; } | ||||
|     UPackage* FindOrAddManagedPackage(FCSNamespace Namespace); | ||||
|  | ||||
|     UCSAssembly* LoadAssemblyByPath(const FString& AssemblyPath, bool bIsCollectible = true); | ||||
|  | ||||
|     // Load an assembly by name that exists in the ProjectRoot/Binaries/Managed folder | ||||
|     UCSAssembly* LoadUserAssemblyByName(const FName AssemblyName, bool bIsCollectible = true); | ||||
|  | ||||
|     // Load an assembly by name that exists in the UnrealSharp/Binaries/Managed folder | ||||
|     UCSAssembly* LoadPluginAssemblyByName(const FName AssemblyName, bool bIsCollectible = true); | ||||
|  | ||||
|     UCSAssembly* FindOwningAssembly(UClass* Class); | ||||
|  | ||||
|     UCSAssembly* FindOwningAssembly(UScriptStruct* Struct); | ||||
|  | ||||
|     UCSAssembly* FindOwningAssembly(UEnum* Enum); | ||||
|  | ||||
|     UCSAssembly* FindAssembly(FName AssemblyName) const | ||||
|     { | ||||
|         return LoadedAssemblies.FindRef(AssemblyName); | ||||
|     } | ||||
|  | ||||
|     UCSAssembly* FindOrLoadAssembly(FName AssemblyName) | ||||
|     { | ||||
|         if (UCSAssembly* Assembly = FindAssembly(AssemblyName)) | ||||
|         { | ||||
|             return Assembly; | ||||
|         } | ||||
|  | ||||
|         return LoadUserAssemblyByName(AssemblyName); | ||||
|     } | ||||
| 	 | ||||
|     FGCHandle FindManagedObject(const UObject* Object); | ||||
|     FGCHandle FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass); | ||||
|  | ||||
|     void SetCurrentWorldContext(UObject* WorldContext) { CurrentWorldContext = WorldContext; } | ||||
|     UObject* GetCurrentWorldContext() const { return CurrentWorldContext.Get(); } | ||||
|  | ||||
|     const FCSManagedPluginCallbacks& GetManagedPluginsCallbacks() const { return ManagedPluginsCallbacks; } | ||||
|  | ||||
|     FOnManagedAssemblyLoaded& OnManagedAssemblyLoadedEvent() { return OnManagedAssemblyLoaded; } | ||||
|     FOnManagedAssemblyUnloaded& OnManagedAssemblyUnloadedEvent() { return OnManagedAssemblyUnloaded; } | ||||
| 	FOnAssembliesReloaded& OnAssembliesLoadedEvent() { return OnAssembliesLoaded; } | ||||
|  | ||||
| #if WITH_EDITOR | ||||
| 	FCSClassEvent& OnNewClassEvent() { return OnNewClass; } | ||||
| 	FCSStructEvent& OnNewStructEvent() { return OnNewStruct; } | ||||
| 	FCSInterfaceEvent& OnNewInterfaceEvent() { return OnNewInterface; } | ||||
| 	FCSEnumEvent& OnNewEnumEvent() { return OnNewEnum; } | ||||
|  | ||||
| 	FSimpleMulticastDelegate& OnProcessedPendingClassesEvent() { return OnProcessedPendingClasses; } | ||||
| #endif | ||||
|  | ||||
| 	void ForEachManagedPackage(const TFunction<void(UPackage*)>& Callback) const | ||||
| 	{ | ||||
| 		for (UPackage* Package : AllPackages) | ||||
| 		{ | ||||
| 			Callback(Package); | ||||
| 		} | ||||
| 	} | ||||
| 	void ForEachManagedField(const TFunction<void(UObject*)>& Callback) const; | ||||
|  | ||||
| 	bool IsManagedPackage(const UPackage* Package) const { 	return AllPackages.Contains(Package); } | ||||
| 	UPackage* GetPackage(const FCSNamespace Namespace); | ||||
|  | ||||
| 	bool IsManagedType(const UObject* Field) const { return IsManagedPackage(Field->GetOutermost()); } | ||||
|  | ||||
| 	bool IsLoadingAnyAssembly() const; | ||||
|  | ||||
| 	void AddDynamicSubsystemClass(TSubclassOf<UDynamicSubsystem> SubsystemClass); | ||||
|  | ||||
| 	UCSTypeBuilderManager* GetTypeBuilderManager() const { return TypeBuilderManager; } | ||||
|  | ||||
| private: | ||||
|  | ||||
| 	friend UCSAssembly; | ||||
| 	friend FUnrealSharpCoreModule; | ||||
|  | ||||
| 	void Initialize(); | ||||
| 	static void Shutdown() { Instance = nullptr; } | ||||
|  | ||||
| 	load_assembly_and_get_function_pointer_fn InitializeNativeHost() const; | ||||
|  | ||||
| 	bool LoadRuntimeHost(); | ||||
| 	bool InitializeDotNetRuntime(); | ||||
| 	bool LoadAllUserAssemblies(); | ||||
|  | ||||
| 	// UObjectArray listener interface | ||||
| 	virtual void NotifyUObjectDeleted(const UObjectBase* Object, int32 Index) override; | ||||
| 	virtual void OnUObjectArrayShutdown() override { GUObjectArray.RemoveUObjectDeleteListener(this); } | ||||
| 	void OnEnginePreExit() { GUObjectArray.RemoveUObjectDeleteListener(this); } | ||||
| 	// End of interface | ||||
|  | ||||
| 	void OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason); | ||||
| 	void TryInitializeDynamicSubsystems(); | ||||
|  | ||||
|     UCSAssembly* FindOwningAssemblySlow(UField* Field); | ||||
|  | ||||
| 	static UCSManager* Instance; | ||||
|  | ||||
| 	UPROPERTY() | ||||
| 	TArray<TObjectPtr<UPackage>> AllPackages; | ||||
|  | ||||
| 	UPROPERTY() | ||||
| 	TObjectPtr<UPackage> GlobalManagedPackage; | ||||
|  | ||||
| 	UPROPERTY(Transient) | ||||
| 	TArray<TSubclassOf<UDynamicSubsystem>> PendingDynamicSubsystemClasses; | ||||
|  | ||||
| 	UPROPERTY(Transient) | ||||
| 	TObjectPtr<UCSTypeBuilderManager> TypeBuilderManager; | ||||
|  | ||||
| 	// Handles to all active UObjects that has a C# counterpart. The key is the unique ID of the UObject. | ||||
| 	TMap<uint32, TSharedPtr<FGCHandle>> ManagedObjectHandles; | ||||
|  | ||||
| 	// Handles all active UObjects that have interface wrappers in C#. The primary key is the unique ID of the UObject. | ||||
| 	// The second key is the unique ID of the interface class. | ||||
| 	TMap<uint32, TMap<uint32, TSharedPtr<FGCHandle>>> ManagedInterfaceWrappers; | ||||
| 	 | ||||
| 	// Map to cache assemblies that native classes are associated with, for quick lookup. | ||||
| 	UPROPERTY() | ||||
| 	TMap<uint32, TObjectPtr<UCSAssembly>> NativeClassToAssemblyMap; | ||||
|  | ||||
| 	UPROPERTY() | ||||
| 	TMap<FName, TObjectPtr<UCSAssembly>> LoadedAssemblies; | ||||
|  | ||||
| 	TWeakObjectPtr<UObject> CurrentWorldContext; | ||||
|  | ||||
| 	FOnManagedAssemblyLoaded OnManagedAssemblyLoaded; | ||||
|     FOnManagedAssemblyUnloaded OnManagedAssemblyUnloaded; | ||||
| 	FOnAssembliesReloaded OnAssembliesLoaded; | ||||
|  | ||||
| #if WITH_EDITORONLY_DATA | ||||
| 	FCSClassEvent OnNewClass; | ||||
| 	FCSStructEvent OnNewStruct; | ||||
| 	FCSInterfaceEvent OnNewInterface; | ||||
| 	FCSEnumEvent OnNewEnum; | ||||
|  | ||||
| 	FSimpleMulticastDelegate OnProcessedPendingClasses; | ||||
| #endif | ||||
|  | ||||
| 	FCSManagedPluginCallbacks ManagedPluginsCallbacks; | ||||
|  | ||||
| 	//.NET Core Host API | ||||
| 	hostfxr_initialize_for_dotnet_command_line_fn Hostfxr_Initialize_For_Dotnet_Command_Line = nullptr; | ||||
| 	hostfxr_initialize_for_runtime_config_fn Hostfxr_Initialize_For_Runtime_Config = nullptr; | ||||
| 	hostfxr_get_runtime_delegate_fn Hostfxr_Get_Runtime_Delegate = nullptr; | ||||
| 	hostfxr_close_fn Hostfxr_Close = nullptr; | ||||
|  | ||||
| 	void* RuntimeHost = nullptr; | ||||
| 	//End | ||||
| }; | ||||
							
								
								
									
										35
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| #include "CSNamespace.h" | ||||
| #include "CSManager.h" | ||||
|  | ||||
| FString FCSNamespace::GetLastNamespace() const | ||||
| { | ||||
| 	FString NamespaceString = Namespace.ToString(); | ||||
| 	int32 LastDotIndex = NamespaceString.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromEnd); | ||||
| 		 | ||||
| 	if (LastDotIndex == INDEX_NONE) | ||||
| 	{ | ||||
| 		return NamespaceString; | ||||
| 	} | ||||
| 		 | ||||
| 	return NamespaceString.Right(NamespaceString.Len() - LastDotIndex - 1); | ||||
| } | ||||
|  | ||||
| bool FCSNamespace::GetParentNamespace(FCSNamespace& OutParent) const | ||||
| { | ||||
| 	FString NamespaceString = Namespace.ToString(); | ||||
| 	int32 LastDotIndex = NamespaceString.Find(".", ESearchCase::CaseSensitive, ESearchDir::FromEnd); | ||||
| 	 | ||||
| 	if (LastDotIndex == INDEX_NONE) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
| 	 | ||||
| 	FString ParentNamespace = NamespaceString.Left(LastDotIndex); | ||||
| 	OutParent = FCSNamespace(*ParentNamespace); | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| UPackage* FCSNamespace::GetPackage() const | ||||
| { | ||||
| 	return UCSManager::Get().FindOrAddManagedPackage(*this); | ||||
| } | ||||
							
								
								
									
										47
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| #pragma once | ||||
|  | ||||
| struct FCSNamespace | ||||
| { | ||||
| 	FCSNamespace(FName InNamespace = NAME_None) : Namespace(InNamespace) | ||||
| 	{ | ||||
| 		 | ||||
| 	} | ||||
|  | ||||
| 	// Get the namespace as a FName | ||||
| 	FName GetFName() const { return Namespace; } | ||||
|  | ||||
| 	// Get the namespace as a string | ||||
| 	FString GetName() const { return Namespace.ToString(); } | ||||
|  | ||||
| 	// Gets the name of the last part of the namespace. For example, if the namespace is "UnrealSharp.Core", this will return "Core". | ||||
| 	FString GetLastNamespace() const; | ||||
|  | ||||
| 	bool GetParentNamespace(FCSNamespace& OutParent) const; | ||||
| 	bool IsValid() const { return Namespace != NAME_None; } | ||||
|  | ||||
| 	UPackage* GetPackage() const; | ||||
|  | ||||
| 	UPackage* TryGetAsNativePackage() const | ||||
| 	{ | ||||
| 		FString NativePackageName = FString::Printf(TEXT("/Script/%s"), *GetLastNamespace()); | ||||
| 		return FindPackage(nullptr, *NativePackageName); | ||||
| 	} | ||||
| 	 | ||||
| 	FName GetPackageName() const { return *FString::Printf(TEXT("/Script/%s"), *Namespace.ToString()); } | ||||
|  | ||||
| 	static FCSNamespace Invalid() { return FCSNamespace(); } | ||||
|  | ||||
| 	bool operator == (const FCSNamespace& Other) const | ||||
| 	{ | ||||
| 		return Namespace == Other.Namespace; | ||||
| 	} | ||||
|  | ||||
| 	friend uint32 GetTypeHash(const FCSNamespace& InNamespace) | ||||
| 	{ | ||||
| 		return GetTypeHash(InNamespace.Namespace); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	FName Namespace; | ||||
| }; | ||||
|  | ||||
| @ -0,0 +1,59 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSUnmanagedDataStore.generated.h" | ||||
|  | ||||
| USTRUCT() | ||||
| struct FUnmanagedDataStore | ||||
| { | ||||
|     GENERATED_BODY() | ||||
|  | ||||
| private: | ||||
|     static constexpr size_t SmallStorageSize = 56; | ||||
|     using FSmallStorage = std::array<std::byte, SmallStorageSize>; | ||||
|  | ||||
|     struct FLargeStorageDeleter  | ||||
|     { | ||||
|         void operator()(void* Ptr) const | ||||
|         { | ||||
|             FMemory::Free(Ptr); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| public: | ||||
|     FUnmanagedDataStore() = default; | ||||
|  | ||||
|     void CopyDataIn(const void* InData, const size_t Size) | ||||
|     { | ||||
|         if (Size <= SmallStorageSize) | ||||
|         { | ||||
|             Data.Emplace<FSmallStorage>(); | ||||
|             FMemory::Memcpy(Data.Get<FSmallStorage>().data(), InData, Size); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Data.Emplace<TSharedPtr<void>>(FMemory::Malloc(Size), FLargeStorageDeleter()); | ||||
|             FMemory::Memcpy(Data.Get<TSharedPtr<void>>().Get(), InData, Size); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void CopyDataOut(void* OutData, const size_t Size) const | ||||
|     { | ||||
|         if (Size <= SmallStorageSize) | ||||
|         { | ||||
|             FMemory::Memcpy(OutData, Data.Get<FSmallStorage>().data(), Size); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             FMemory::Memcpy(OutData, Data.Get<TSharedPtr<void>>().Get(), Size); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     TVariant<FSmallStorage, TSharedPtr<void>> Data; | ||||
|      | ||||
| }; | ||||
| @ -0,0 +1,55 @@ | ||||
| #include "CSUnrealSharpSettings.h" | ||||
|  | ||||
| UCSUnrealSharpSettings::UCSUnrealSharpSettings() | ||||
| { | ||||
| 	CategoryName = "Plugins"; | ||||
| } | ||||
|  | ||||
| #if WITH_EDITOR | ||||
| void UCSUnrealSharpSettings::PreEditChange(FProperty* PropertyAboutToChange) | ||||
| { | ||||
| 	Super::PreEditChange(PropertyAboutToChange); | ||||
|  | ||||
| 	if (PropertyAboutToChange->GetFName() == GET_MEMBER_NAME_CHECKED(UCSUnrealSharpSettings, bEnableNamespaceSupport)) | ||||
| 	{ | ||||
| 		OldValueOfNamespaceSupport = bEnableNamespaceSupport; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void UCSUnrealSharpSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) | ||||
| { | ||||
| 	Super::PostEditChangeProperty(PropertyChangedEvent); | ||||
|  | ||||
| 	if (PropertyChangedEvent.Property) | ||||
| 	{ | ||||
| 		const FName PropertyName = PropertyChangedEvent.Property->GetFName(); | ||||
| 		if (PropertyName == GET_MEMBER_NAME_CHECKED(UCSUnrealSharpSettings, bEnableNamespaceSupport)) | ||||
| 		{ | ||||
| 			bRecentlyChangedNamespaceSupport = true; | ||||
|  | ||||
| 			FText Message = FText::FromString( | ||||
| 				TEXT("Namespace support settings have been updated. A restart is required for the changes to take effect.\n\n" | ||||
| 					 "WARNING: This experimental feature will break existing Blueprints derived from C# classes due to changes in the outermost package when restarting the engine.\n\n" | ||||
| 					 "Press 'Cancel' to revert these changes.") | ||||
| 			); | ||||
| 			 | ||||
| 			if (FMessageDialog::Open(EAppMsgType::OkCancel, Message) == EAppReturnType::Cancel) | ||||
| 			{ | ||||
| 				bEnableNamespaceSupport = OldValueOfNamespaceSupport; | ||||
| 				bRecentlyChangedNamespaceSupport = false; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| #endif | ||||
|  | ||||
| bool UCSUnrealSharpSettings::HasNamespaceSupport() const | ||||
| { | ||||
| 	if (bRecentlyChangedNamespaceSupport) | ||||
| 	{ | ||||
| 		// Keep returning the old value until we have restarted the editor | ||||
| 		return OldValueOfNamespaceSupport; | ||||
| 	} | ||||
| 	 | ||||
| 	return bEnableNamespaceSupport; | ||||
| } | ||||
| @ -0,0 +1,39 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "Engine/DeveloperSettings.h" | ||||
| #include "CSUnrealSharpSettings.generated.h" | ||||
|  | ||||
| UCLASS(config = UnrealSharp, defaultconfig, meta = (DisplayName = "UnrealSharp Settings")) | ||||
| class UNREALSHARPCORE_API UCSUnrealSharpSettings : public UDeveloperSettings | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| 	 | ||||
| public: | ||||
|  | ||||
| 	UCSUnrealSharpSettings(); | ||||
|  | ||||
| #if WITH_EDITOR | ||||
| 	// UObject interface | ||||
| 	virtual void PreEditChange(FProperty* PropertyAboutToChange) override; | ||||
| 	virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override; | ||||
| 	// End of UObject interface | ||||
| #endif | ||||
| 	 | ||||
| 	// Should we exit PIE when an exception is thrown in C#? | ||||
| 	UPROPERTY(EditDefaultsOnly, config, Category = "UnrealSharp | Debugging") | ||||
| 	bool bCrashOnException = true; | ||||
|  | ||||
| 	bool HasNamespaceSupport() const; | ||||
|  | ||||
| protected: | ||||
| 	 | ||||
| 	// Should we enable namespace support for generated types? | ||||
| 	// If false, all types will be generated in the global package and all types need to have unique names. | ||||
| 	// Currently destructive to the project if changed after BPs of C# types have been created. | ||||
| 	UPROPERTY(EditDefaultsOnly, config, Category = "UnrealSharp | Namespace", Experimental) | ||||
| 	bool bEnableNamespaceSupport = false; | ||||
|  | ||||
| 	bool bRecentlyChangedNamespaceSupport = false; | ||||
| 	bool OldValueOfNamespaceSupport = false; | ||||
| }; | ||||
| @ -0,0 +1,23 @@ | ||||
| #include "AsyncExporter.h" | ||||
| #include "CSManagedDelegate.h" | ||||
|  | ||||
| void UAsyncExporter::RunOnThread(TWeakObjectPtr<UObject> WorldContextObject, ENamedThreads::Type Thread, FGCHandleIntPtr DelegateHandle) | ||||
| { | ||||
| 	AsyncTask(Thread, [WorldContextObject, DelegateHandle]() | ||||
| 	{ | ||||
| 		FCSManagedDelegate ManagedDelegate = FGCHandle(DelegateHandle, GCHandleType::StrongHandle); | ||||
| 		 | ||||
| 		if (!WorldContextObject.IsValid()) | ||||
| 		{ | ||||
| 			ManagedDelegate.Dispose(); | ||||
| 			return; | ||||
| 		} | ||||
| 		 | ||||
| 		ManagedDelegate.Invoke(WorldContextObject.Get()); | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| int UAsyncExporter::GetCurrentNamedThread() | ||||
| { | ||||
| 	return FTaskGraphInterface::Get().GetCurrentThreadIfKnown(); | ||||
| } | ||||
| @ -0,0 +1,22 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "Async/Async.h" | ||||
| #include "CSManagedGCHandle.h" | ||||
| #include "AsyncExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UAsyncExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RunOnThread(TWeakObjectPtr<UObject> WorldContextObject, ENamedThreads::Type Thread, FGCHandleIntPtr DelegateHandle); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int GetCurrentNamedThread(); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,11 @@ | ||||
| #include "CSTimerExtensions.h" | ||||
|  | ||||
| void UCSTimerExtensions::SetTimerForNextTick(FNextTickEvent NextTickEvent) | ||||
| { | ||||
| #if WITH_EDITOR | ||||
| 	FFunctionGraphTask::CreateAndDispatchWhenReady([NextTickEvent] | ||||
| 	{ | ||||
| 		GEditor->GetTimerManager()->SetTimerForNextTick(FTimerDelegate::CreateLambda(NextTickEvent)); | ||||
| 	}, TStatId(), nullptr, ENamedThreads::GameThread); | ||||
| #endif | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "CSTimerExtensions.generated.h" | ||||
|  | ||||
| using FNextTickEvent = void(*)(); | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UCSTimerExtensions : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| 	 | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void SetTimerForNextTick(FNextTickEvent NextTickEvent); | ||||
| }; | ||||
| @ -0,0 +1,43 @@ | ||||
| #include "FArrayPropertyExporter.h" | ||||
|  | ||||
| void UFArrayPropertyExporter::InitializeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.EmptyAndAddValues(Length); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::EmptyArray(FArrayProperty* ArrayProperty, const void* ScriptArray) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.EmptyValues(); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::AddToArray(FArrayProperty* ArrayProperty, const void* ScriptArray) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.AddValue(); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::InsertInArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.InsertValues(index); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::RemoveFromArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.RemoveValues(index); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::ResizeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.Resize(Length); | ||||
| } | ||||
|  | ||||
| void UFArrayPropertyExporter::SwapValues(FArrayProperty* ArrayProperty, const void* ScriptArray, int indexA, int indexB) | ||||
| { | ||||
| 	FScriptArrayHelper Helper(ArrayProperty, ScriptArray); | ||||
| 	Helper.SwapValues(indexA, indexB); | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FArrayPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFArrayPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void InitializeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void EmptyArray(FArrayProperty* ArrayProperty, const void* ScriptArray); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void AddToArray(FArrayProperty* ArrayProperty, const void* ScriptArray); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void InsertInArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RemoveFromArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void ResizeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void SwapValues(FArrayProperty* ArrayProperty, const void* ScriptArray, int indexA, int indexB); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,21 @@ | ||||
| #include "FBoolPropertyExporter.h" | ||||
|  | ||||
| bool UFBoolPropertyExporter::GetBitfieldValueFromProperty(uint8* NativeBuffer, FProperty* Property, int32 Offset) | ||||
| { | ||||
| 	// NativeBuffer won't necessarily correspond to a UObject.  It might be the beginning of a native struct, for example. | ||||
| 	check(NativeBuffer); | ||||
| 	uint8* OffsetPointer = NativeBuffer + Offset; | ||||
| 	check(OffsetPointer == Property->ContainerPtrToValuePtr<uint8>(NativeBuffer)); | ||||
| 	FBoolProperty* BoolProperty = CastFieldChecked<FBoolProperty>(Property); | ||||
| 	return BoolProperty->GetPropertyValue(OffsetPointer); | ||||
| } | ||||
|  | ||||
| void UFBoolPropertyExporter::SetBitfieldValueForProperty(uint8* NativeObject, FProperty* Property, int32 Offset, bool Value) | ||||
| { | ||||
| 	// NativeBuffer won't necessarily correspond to a UObject.  It might be the beginning of a native struct, for example. | ||||
| 	check(NativeObject); | ||||
| 	uint8* OffsetPointer = NativeObject + Offset; | ||||
| 	check(OffsetPointer == Property->ContainerPtrToValuePtr<uint8>(NativeObject)); | ||||
| 	const FBoolProperty* BoolProperty = CastFieldChecked<FBoolProperty>(Property); | ||||
| 	BoolProperty->SetPropertyValue(OffsetPointer, Value); | ||||
| } | ||||
| @ -0,0 +1,21 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FBoolPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFBoolPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool GetBitfieldValueFromProperty(uint8* NativeBuffer, FProperty* Property, int32 Offset); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void SetBitfieldValueForProperty(uint8* NativeObject, FProperty* Property, int32 Offset, bool Value); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,7 @@ | ||||
| #include "FCSManagedCallbacksExporter.h" | ||||
| #include "CSManagedCallbacksCache.h" | ||||
|  | ||||
| FCSManagedCallbacks::FManagedCallbacks* UFCSManagedCallbacksExporter::GetManagedCallbacks() | ||||
| { | ||||
| 	return &FCSManagedCallbacks::ManagedCallbacks; | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "CSManagedCallbacksCache.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FCSManagedCallbacksExporter.generated.h" | ||||
|  | ||||
| class FCSManagedCallbacks; | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFCSManagedCallbacksExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FCSManagedCallbacks::FManagedCallbacks* GetManagedCallbacks(); | ||||
| }; | ||||
| @ -0,0 +1,23 @@ | ||||
| #include "FCSManagerExporter.h" | ||||
| #include "UnrealSharpCore/CSManager.h" | ||||
|  | ||||
| void* UFCSManagerExporter::FindManagedObject(UObject* Object) | ||||
| { | ||||
| 	return UCSManager::Get().FindManagedObject(Object); | ||||
| } | ||||
|  | ||||
| void* UFCSManagerExporter::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* NativeClass) | ||||
| { | ||||
| 	return UCSManager::Get().FindOrCreateManagedInterfaceWrapper(Object, NativeClass); | ||||
| } | ||||
|  | ||||
| void* UFCSManagerExporter::GetCurrentWorldContext() | ||||
| { | ||||
| 	return UCSManager::Get().GetCurrentWorldContext(); | ||||
| } | ||||
|  | ||||
| void* UFCSManagerExporter::GetCurrentWorldPtr() | ||||
| { | ||||
| 	UObject* WorldContext = UCSManager::Get().GetCurrentWorldContext(); | ||||
| 	return GEngine->GetWorldFromContextObject(WorldContext, EGetWorldErrorMode::ReturnNull); | ||||
| } | ||||
| @ -0,0 +1,28 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FCSManagerExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFCSManagerExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* FindManagedObject(UObject* Object); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* NativeClass); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetCurrentWorldContext(); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetCurrentWorldPtr(); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,6 @@ | ||||
| #include "FCSTypeRegistryExporter.h" | ||||
|  | ||||
| void UFCSTypeRegistryExporter::RegisterClassToFilePath(const UTF16CHAR* ClassName, const UTF16CHAR* FilePath) | ||||
| { | ||||
| 	//FCSTypeRegistry::Get().RegisterClassToFilePath(ClassName, FilePath); | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FCSTypeRegistryExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UFCSTypeRegistryExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RegisterClassToFilePath(const UTF16CHAR* ClassName, const UTF16CHAR* FilePath); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,30 @@ | ||||
| #include "FEditorDelegatesExporter.h" | ||||
|  | ||||
| void UFEditorDelegatesExporter::BindEndPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle) | ||||
| { | ||||
| #if WITH_EDITOR | ||||
| 	*DelegateHandle = FEditorDelegates::EndPIE.AddLambda(Delegate); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void UFEditorDelegatesExporter::BindStartPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle) | ||||
| { | ||||
| #if WITH_EDITOR | ||||
| 	*DelegateHandle = FEditorDelegates::BeginPIE.AddLambda(Delegate); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void UFEditorDelegatesExporter::UnbindStartPIE(FDelegateHandle DelegateHandle) | ||||
| { | ||||
| #if WITH_EDITOR | ||||
| 	FEditorDelegates::BeginPIE.Remove(DelegateHandle); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void UFEditorDelegatesExporter::UnbindEndPIE(FDelegateHandle DelegateHandle) | ||||
| { | ||||
| #if WITH_EDITOR | ||||
| 	FEditorDelegates::EndPIE.Remove(DelegateHandle); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,27 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FEditorDelegatesExporter.generated.h" | ||||
|  | ||||
| using FPIEEvent = void(*)(bool); | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFEditorDelegatesExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| 	 | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void BindEndPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void BindStartPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void UnbindEndPIE(FDelegateHandle DelegateHandle); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void UnbindStartPIE(FDelegateHandle DelegateHandle); | ||||
| }; | ||||
| @ -0,0 +1,31 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
|  | ||||
| #include "FFieldPathExporter.h" | ||||
|  | ||||
| bool UFFieldPathExporter::IsValid(const TFieldPath<FField>& FieldPath) | ||||
| { | ||||
| 	return FieldPath != nullptr; | ||||
| } | ||||
|  | ||||
| bool UFFieldPathExporter::IsStale(const FFieldPath& FieldPath) | ||||
| { | ||||
| 	return FieldPath.IsStale(); | ||||
| } | ||||
|  | ||||
| void UFFieldPathExporter::FieldPathToString(const FFieldPath& FieldPath, FString* OutString) | ||||
| { | ||||
| 	*OutString = FieldPath.ToString(); | ||||
| } | ||||
|  | ||||
| bool UFFieldPathExporter::FieldPathsEqual(const FFieldPath& A, const FFieldPath& B) | ||||
| { | ||||
| 	return A == B; | ||||
| } | ||||
|  | ||||
| int32 UFFieldPathExporter::GetFieldPathHashCode(const FFieldPath& FieldPath) | ||||
| { | ||||
| 	// GetHashCode returns a signed integer in C#, but GetTypeHash returns an unsigned integer, thus | ||||
| 	// the cast is necessary | ||||
| 	return static_cast<int32>(GetTypeHash(FieldPath)); | ||||
| } | ||||
| @ -0,0 +1,30 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FFieldPathExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFFieldPathExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsValid(const TFieldPath<FField>& FieldPath); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsStale(const FFieldPath& FieldPath); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void FieldPathToString(const FFieldPath& FieldPath, FString* OutString); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool FieldPathsEqual(const FFieldPath& A, const FFieldPath& B); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetFieldPathHashCode(const FFieldPath& FieldPath); | ||||
| }; | ||||
| @ -0,0 +1,38 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
|  | ||||
| #include "FInstancedStructExporter.h" | ||||
|  | ||||
| #include "StructUtils/InstancedStruct.h" | ||||
|  | ||||
| const UScriptStruct* UFInstancedStructExporter::GetNativeStruct(const FInstancedStruct& Struct) | ||||
| { | ||||
| 	check(&Struct != nullptr); | ||||
| 	return Struct.GetScriptStruct(); | ||||
| } | ||||
|  | ||||
| void UFInstancedStructExporter::NativeInit(FInstancedStruct& Struct) | ||||
| { | ||||
| 	std::construct_at(&Struct); | ||||
| } | ||||
|  | ||||
| void UFInstancedStructExporter::NativeCopy(FInstancedStruct& Dest, const FInstancedStruct& Src) | ||||
| { | ||||
| 	std::construct_at(&Dest, Src); | ||||
| } | ||||
|  | ||||
| void UFInstancedStructExporter::NativeDestroy(FInstancedStruct& Struct) | ||||
| { | ||||
| 	std::destroy_at(&Struct); | ||||
| } | ||||
|  | ||||
| void UFInstancedStructExporter::InitializeAs(FInstancedStruct& Struct, const UScriptStruct* ScriptStruct, const uint8* StructData) | ||||
| { | ||||
| 	check(ScriptStruct != nullptr); | ||||
| 	Struct.InitializeAs(ScriptStruct, StructData); | ||||
| } | ||||
|  | ||||
| const uint8* UFInstancedStructExporter::GetMemory(const FInstancedStruct& Struct) | ||||
| { | ||||
| 	return Struct.GetMemory(); | ||||
| } | ||||
| @ -0,0 +1,37 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FInstancedStructExporter.generated.h" | ||||
|  | ||||
| struct FInstancedStruct; | ||||
| /** | ||||
|  *  | ||||
|  */ | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFInstancedStructExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static const UScriptStruct* GetNativeStruct(const FInstancedStruct& Struct); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void NativeInit(FInstancedStruct& Struct); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void NativeCopy(FInstancedStruct& Dest, const FInstancedStruct& Src); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void NativeDestroy(FInstancedStruct& Struct); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void InitializeAs(FInstancedStruct& Struct, const UScriptStruct* ScriptStruct, const uint8* StructData); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static const uint8* GetMemory(const FInstancedStruct& Struct); | ||||
| }; | ||||
| @ -0,0 +1,11 @@ | ||||
| #include "FMapPropertyExporter.h" | ||||
|  | ||||
| void* UFMapPropertyExporter::GetKey(FMapProperty* MapProperty) | ||||
| { | ||||
| 	return MapProperty->KeyProp; | ||||
| } | ||||
|  | ||||
| void* UFMapPropertyExporter::GetValue(FMapProperty* MapProperty) | ||||
| { | ||||
| 	return MapProperty->ValueProp; | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FMapPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFMapPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetKey(FMapProperty* MapProperty); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetValue(FMapProperty* MapProperty); | ||||
| }; | ||||
| @ -0,0 +1,6 @@ | ||||
| #include "FMatrixExporter.h" | ||||
|  | ||||
| void UFMatrixExporter::FromRotator(FMatrix* Matrix, const FRotator Rotator) | ||||
| { | ||||
| 	*Matrix = Rotator.Quaternion().ToMatrix(); | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FMatrixExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFMatrixExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void FromRotator(FMatrix* Matrix, const FRotator Rotator); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,9 @@ | ||||
| #include "FMsgExporter.h" | ||||
|  | ||||
| void UFMsgExporter::Log(const UTF16CHAR* ManagedCategoryName, ELogVerbosity::Type Verbosity, const UTF16CHAR* ManagedMessage) | ||||
| { | ||||
| 	FString Message = FString(ManagedMessage); | ||||
| 	FName CategoryName = FName(ManagedCategoryName); | ||||
| 	 | ||||
| 	FMsg::Logf(nullptr, 0, CategoryName, Verbosity, TEXT("%s"), *Message); | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FMsgExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFMsgExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void Log(const UTF16CHAR* ManagedCategoryName, ELogVerbosity::Type Verbosity, const UTF16CHAR* ManagedMessage); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,64 @@ | ||||
| #include "FMulticastDelegatePropertyExporter.h" | ||||
|  | ||||
| void UFMulticastDelegatePropertyExporter::AddDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName) | ||||
| { | ||||
| 	FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName); | ||||
| 	DelegateProperty->AddDelegate(NewScriptDelegate, nullptr, Delegate); | ||||
| } | ||||
|  | ||||
| bool UFMulticastDelegatePropertyExporter::IsBound(FMulticastScriptDelegate* Delegate) | ||||
| { | ||||
| 	return Delegate->IsBound(); | ||||
| } | ||||
|  | ||||
| void UFMulticastDelegatePropertyExporter::ToString(FMulticastScriptDelegate* Delegate, FString* OutString) | ||||
| { | ||||
| 	*OutString = Delegate->ToString<UObject>(); | ||||
| } | ||||
|  | ||||
| void UFMulticastDelegatePropertyExporter::RemoveDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName) | ||||
| { | ||||
| 	FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName); | ||||
| 	DelegateProperty->RemoveDelegate(NewScriptDelegate, nullptr, Delegate); | ||||
| } | ||||
|  | ||||
| void UFMulticastDelegatePropertyExporter::ClearDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate) | ||||
| { | ||||
| 	DelegateProperty->ClearDelegate(nullptr, Delegate); | ||||
| } | ||||
|  | ||||
| void UFMulticastDelegatePropertyExporter::BroadcastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, void* Parameters) | ||||
| { | ||||
| 	Delegate = TryGetSparseMulticastDelegate(DelegateProperty, Delegate); | ||||
| 	Delegate->ProcessMulticastDelegate<UObject>(Parameters); | ||||
| } | ||||
|  | ||||
| bool UFMulticastDelegatePropertyExporter::ContainsDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName) | ||||
| { | ||||
| 	FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName); | ||||
| 	Delegate = TryGetSparseMulticastDelegate(DelegateProperty, Delegate); | ||||
| 	return Delegate->Contains(NewScriptDelegate); | ||||
| } | ||||
|  | ||||
| void* UFMulticastDelegatePropertyExporter::GetSignatureFunction(FMulticastDelegateProperty* DelegateProperty) | ||||
| { | ||||
| 	return DelegateProperty->SignatureFunction; | ||||
| } | ||||
|  | ||||
| FScriptDelegate UFMulticastDelegatePropertyExporter::MakeScriptDelegate(UObject* Target, const char* FunctionName) | ||||
| { | ||||
| 	FScriptDelegate NewDelegate; | ||||
| 	NewDelegate.BindUFunction(Target, FunctionName); | ||||
| 	return NewDelegate; | ||||
| } | ||||
|  | ||||
| const FMulticastScriptDelegate* UFMulticastDelegatePropertyExporter::TryGetSparseMulticastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate) | ||||
| { | ||||
| 	// If the delegate is a sparse delegate, we need to get the multicast delegate from FSparseDelegate wrapper. | ||||
| 	if (DelegateProperty->IsA<FMulticastSparseDelegateProperty>()) | ||||
| 	{ | ||||
| 		Delegate = DelegateProperty->GetMulticastDelegate(Delegate); | ||||
| 	} | ||||
|  | ||||
| 	return Delegate; | ||||
| } | ||||
| @ -0,0 +1,58 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FMulticastDelegatePropertyExporter.generated.h" | ||||
|  | ||||
| struct Interop_FScriptDelegate | ||||
| { | ||||
| 	UObject* Object; | ||||
| 	FName Name; | ||||
|  | ||||
| 	FScriptDelegate ToFScriptDelegate() const | ||||
| 	{ | ||||
| 		FScriptDelegate NewScriptDelegate; | ||||
| 		NewScriptDelegate.BindUFunction(Object, Name); | ||||
| 		return NewScriptDelegate; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFMulticastDelegatePropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void AddDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsBound(FMulticastScriptDelegate* Delegate); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void ToString(FMulticastScriptDelegate* Delegate, FString* OutString); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RemoveDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void ClearDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void BroadcastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, void* Parameters); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool ContainsDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetSignatureFunction(FMulticastDelegateProperty* DelegateProperty); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FScriptDelegate MakeScriptDelegate(UObject* Target, const char* FunctionName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static const FMulticastScriptDelegate* TryGetSparseMulticastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,17 @@ | ||||
| #include "FNameExporter.h" | ||||
|  | ||||
| void UFNameExporter::NameToString(FName Name, FString* OutString) | ||||
| { | ||||
| 	Name.ToString(*OutString); | ||||
| } | ||||
|  | ||||
| void UFNameExporter::StringToName(FName* Name, const UTF16CHAR* String, int32 Length) | ||||
| { | ||||
| 	*Name = FName(TStringView(String, Length)); | ||||
| } | ||||
|  | ||||
| bool UFNameExporter::IsValid(FName Name) | ||||
| { | ||||
| 	bool bIsValid = Name.IsValid(); | ||||
| 	return bIsValid; | ||||
| } | ||||
| @ -0,0 +1,23 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FNameExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFNameExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void NameToString(FName Name, FString* OutString); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void StringToName(FName* Name, const UTF16CHAR* String, int32 Length); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsValid(FName Name); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,62 @@ | ||||
| #include "FOptionalPropertyExporter.h" | ||||
| #include "UObject/PropertyOptional.h" | ||||
|  | ||||
| bool UFOptionalPropertyExporter::IsSet(const FOptionalProperty* OptionalProperty, const void* ScriptValue) | ||||
| { | ||||
| 	return OptionalProperty->IsSet(ScriptValue); | ||||
| } | ||||
|  | ||||
| void* UFOptionalPropertyExporter::MarkSetAndGetInitializedValuePointerToReplace(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->MarkSetAndGetInitializedValuePointerToReplace(Data); | ||||
| } | ||||
|  | ||||
| void UFOptionalPropertyExporter::MarkUnset(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->MarkUnset(Data); | ||||
| } | ||||
|  | ||||
| const void* UFOptionalPropertyExporter::GetValuePointerForRead(const FOptionalProperty* OptionalProperty, const void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForRead(Data); | ||||
| } | ||||
|  | ||||
| void* UFOptionalPropertyExporter::GetValuePointerForReplace(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForReplace(Data); | ||||
| } | ||||
|  | ||||
| const void* UFOptionalPropertyExporter::GetValuePointerForReadIfSet(const FOptionalProperty* OptionalProperty, const void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForReadIfSet(Data); | ||||
| } | ||||
|  | ||||
| void* UFOptionalPropertyExporter::GetValuePointerForReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForReplaceIfSet(Data); | ||||
| } | ||||
|  | ||||
| void* UFOptionalPropertyExporter::GetValuePointerForReadOrReplace(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForReadOrReplace(Data); | ||||
| } | ||||
|  | ||||
| void* UFOptionalPropertyExporter::GetValuePointerForReadOrReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
| 	return OptionalProperty->GetValuePointerForReadOrReplaceIfSet(Data); | ||||
| } | ||||
|  | ||||
| int32 UFOptionalPropertyExporter::CalcSize(const FOptionalProperty* OptionalProperty) | ||||
| { | ||||
| #if ENGINE_MINOR_VERSION >= 5 | ||||
| 	// Do we really need this? StaticLink should do this. | ||||
| 	return OptionalProperty->CalcSize(); | ||||
| #else | ||||
| 	return OptionalProperty->GetSize(); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void UFOptionalPropertyExporter::DestructInstance(const FOptionalProperty* OptionalProperty, void* Data) | ||||
| { | ||||
|     OptionalProperty->DestroyValueInternal(Data); | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FOptionalPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFOptionalPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| 	 | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsSet(const FOptionalProperty* OptionalProperty, const void* ScriptValue); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* MarkSetAndGetInitializedValuePointerToReplace(const FOptionalProperty* OptionalProperty, void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void MarkUnset(const FOptionalProperty* OptionalProperty, void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static const void* GetValuePointerForRead(const FOptionalProperty* OptionalProperty, const void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetValuePointerForReplace(const FOptionalProperty* OptionalProperty, void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static const void* GetValuePointerForReadIfSet(const FOptionalProperty* OptionalProperty, const void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetValuePointerForReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetValuePointerForReadOrReplace(const FOptionalProperty* OptionalProperty, void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetValuePointerForReadOrReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 CalcSize(const FOptionalProperty* OptionalProperty); | ||||
|  | ||||
|     UNREALSHARP_FUNCTION() | ||||
|     static void DestructInstance(const FOptionalProperty* OptionalProperty, void* Data); | ||||
| }; | ||||
| @ -0,0 +1,106 @@ | ||||
| #include "FPropertyExporter.h" | ||||
|  | ||||
| FProperty* UFPropertyExporter::GetNativePropertyFromName(UStruct* Struct, const char* PropertyName) | ||||
| { | ||||
| 	FProperty* Property = FindFProperty<FProperty>(Struct, PropertyName); | ||||
| 	return Property; | ||||
| } | ||||
|  | ||||
| int32 UFPropertyExporter::GetPropertyOffset(FProperty* Property) | ||||
| { | ||||
| 	return Property->GetOffset_ForInternal(); | ||||
| } | ||||
|  | ||||
| int32 UFPropertyExporter::GetSize(FProperty* Property) | ||||
| { | ||||
| 	return Property->GetSize(); | ||||
| } | ||||
|  | ||||
| int32 UFPropertyExporter::GetArrayDim(FProperty* Property) | ||||
| { | ||||
| 	return Property->ArrayDim; | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::DestroyValue(FProperty* Property, void* Value) | ||||
| { | ||||
| 	Property->DestroyValue(Value); | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::DestroyValue_InContainer(FProperty* Property, void* Value) | ||||
| { | ||||
| 	Property->DestroyValue_InContainer(Value); | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::InitializeValue(FProperty* Property, void* Value) | ||||
| { | ||||
| 	Property->InitializeValue(Value); | ||||
| } | ||||
|  | ||||
| bool UFPropertyExporter::Identical(const FProperty* Property, void* ValueA, void* ValueB) | ||||
| { | ||||
| 	bool bIsIdentical = Property->Identical(ValueA, ValueB); | ||||
| 	return bIsIdentical; | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::GetInnerFields(FProperty* SetProperty, TArray<FField*>* OutFields) | ||||
| { | ||||
| 	SetProperty->GetInnerFields(*OutFields); | ||||
| } | ||||
|  | ||||
| uint32 UFPropertyExporter::GetValueTypeHash(FProperty* Property, void* Source) | ||||
| { | ||||
| 	return Property->GetValueTypeHash(Source); | ||||
| } | ||||
|  | ||||
| bool UFPropertyExporter::HasAnyPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck) | ||||
| { | ||||
| 	return Property->HasAnyPropertyFlags(FlagsToCheck); | ||||
| } | ||||
|  | ||||
| bool UFPropertyExporter::HasAllPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck) | ||||
| { | ||||
| 	return Property->HasAllPropertyFlags(FlagsToCheck); | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::CopySingleValue(FProperty* Property, void* Dest, void* Src) | ||||
| { | ||||
| 	Property->CopySingleValue(Dest, Src); | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::GetValue_InContainer(FProperty* Property, void* Container, void* OutValue) | ||||
| { | ||||
| 	Property->GetValue_InContainer(Container, OutValue); | ||||
| } | ||||
|  | ||||
| void UFPropertyExporter::SetValue_InContainer(FProperty* Property, void* Container, void* Value) | ||||
| { | ||||
| 	Property->SetValue_InContainer(Container, Value); | ||||
| } | ||||
|  | ||||
| uint8 UFPropertyExporter::GetBoolPropertyFieldMaskFromName(UStruct* InStruct, const char* InPropertyName) | ||||
| { | ||||
| 	FBoolProperty* Property = FindFProperty<FBoolProperty>(InStruct, InPropertyName); | ||||
| 	if (!Property) | ||||
| 	{ | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	return Property->GetFieldMask(); | ||||
| } | ||||
|  | ||||
| int32 UFPropertyExporter::GetPropertyOffsetFromName(UStruct* InStruct, const char* InPropertyName) | ||||
| { | ||||
| 	FProperty* FoundProperty = GetNativePropertyFromName(InStruct, InPropertyName); | ||||
| 	if (!FoundProperty) | ||||
| 	{ | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	return GetPropertyOffset(FoundProperty); | ||||
| } | ||||
|  | ||||
| int32 UFPropertyExporter::GetPropertyArrayDimFromName(UStruct* InStruct, const char* PropertyName) | ||||
| { | ||||
| 	FProperty* Property = GetNativePropertyFromName(InStruct, PropertyName); | ||||
| 	return GetArrayDim(Property); | ||||
| } | ||||
| @ -0,0 +1,69 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FProperty* GetNativePropertyFromName(UStruct* Struct, const char* PropertyName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetPropertyOffsetFromName(UStruct* InStruct, const char* InPropertyName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetPropertyArrayDimFromName(UStruct* InStruct, const char* PropertyName); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetPropertyOffset(FProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetSize(FProperty* Property); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 GetArrayDim(FProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void DestroyValue(FProperty* Property, void* Value); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void DestroyValue_InContainer(FProperty* Property, void* Value); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void InitializeValue(FProperty* Property, void* Value); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool Identical(const FProperty* Property, void* ValueA, void* ValueB); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void GetInnerFields(FProperty* SetProperty, TArray<FField*>* OutFields); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static uint32 GetValueTypeHash(FProperty* Property, void* Source); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool HasAnyPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool HasAllPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void CopySingleValue(FProperty* Property, void* Dest, void* Src); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void GetValue_InContainer(FProperty* Property, void* Container, void* OutValue); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void SetValue_InContainer(FProperty* Property, void* Container, void* Value); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static uint8 GetBoolPropertyFieldMaskFromName(UStruct* InStruct, const char* InPropertyName); | ||||
| }; | ||||
| @ -0,0 +1,37 @@ | ||||
| #include "FRandomStreamExporter.h" | ||||
|  | ||||
| void UFRandomStreamExporter::GenerateNewSeed(FRandomStream* RandomStream) | ||||
| { | ||||
| 	RandomStream->GenerateNewSeed(); | ||||
| } | ||||
|  | ||||
| float UFRandomStreamExporter::GetFraction(FRandomStream* RandomStream) | ||||
| { | ||||
| 	return RandomStream->GetFraction(); | ||||
| } | ||||
|  | ||||
| uint32 UFRandomStreamExporter::GetUnsignedInt(FRandomStream* RandomStream) | ||||
| { | ||||
| 	return RandomStream->GetUnsignedInt(); | ||||
| } | ||||
|  | ||||
| FVector UFRandomStreamExporter::GetUnitVector(FRandomStream* RandomStream) | ||||
| { | ||||
| 	return RandomStream->GetUnitVector(); | ||||
| } | ||||
|  | ||||
| int UFRandomStreamExporter::RandRange(FRandomStream* RandomStream, int32 Min, int32 Max) | ||||
| { | ||||
| 	return RandomStream->RandRange(Min, Max); | ||||
| } | ||||
|  | ||||
| FVector UFRandomStreamExporter::VRandCone(FRandomStream* RandomStream, FVector Dir, float ConeHalfAngleRad) | ||||
| { | ||||
| 	return RandomStream->VRandCone(Dir, ConeHalfAngleRad); | ||||
| } | ||||
|  | ||||
| FVector UFRandomStreamExporter::VRandCone2(FRandomStream* RandomStream, FVector Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad) | ||||
| { | ||||
| 	return RandomStream->VRandCone(Dir, HorizontalConeHalfAngleRad, VerticalConeHalfAngleRad); | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,35 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FRandomStreamExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFRandomStreamExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void GenerateNewSeed(FRandomStream* RandomStream); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static float GetFraction(FRandomStream* RandomStream); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static uint32 GetUnsignedInt(FRandomStream* RandomStream); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FVector GetUnitVector(FRandomStream* RandomStream); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int RandRange(FRandomStream* RandomStream, int32 Min, int32 Max); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FVector VRandCone(FRandomStream* RandomStream, FVector Dir, float ConeHalfAngleRad); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static FVector VRandCone2(FRandomStream* RandomStream, FVector Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,8 @@ | ||||
| #include "FRotatorExporter.h" | ||||
|  | ||||
| void UFRotatorExporter::FromMatrix(FRotator* Rotator, const FMatrix& Matrix) | ||||
| { | ||||
| 	*Rotator = Matrix.Rotator(); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FRotatorExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFRotatorExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void FromMatrix(FRotator* Rotator, const FMatrix& Matrix); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,21 @@ | ||||
| #include "FScriptArrayExporter.h" | ||||
|  | ||||
| void* UFScriptArrayExporter::GetData(FScriptArray* Instance) | ||||
| { | ||||
| 	return Instance->GetData(); | ||||
| } | ||||
|  | ||||
| bool UFScriptArrayExporter::IsValidIndex(FScriptArray* Instance, int32 i) | ||||
| { | ||||
| 	return Instance->IsValidIndex(i); | ||||
| } | ||||
|  | ||||
| int UFScriptArrayExporter::Num(FScriptArray* Instance) | ||||
| { | ||||
| 	return Instance->Num(); | ||||
| } | ||||
|  | ||||
| void UFScriptArrayExporter::Destroy(FScriptArray* Instance) | ||||
| { | ||||
| 	Instance->~FScriptArray(); | ||||
| } | ||||
| @ -0,0 +1,26 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FScriptArrayExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFScriptArrayExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetData(FScriptArray* Instance); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsValidIndex(FScriptArray* Instance, int32 i); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int Num(FScriptArray* Instance); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void Destroy(FScriptArray* Instance); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,11 @@ | ||||
| #include "FScriptDelegateExporter.h" | ||||
|  | ||||
| void UFScriptDelegateExporter::BroadcastDelegate(FScriptDelegate* Delegate, void* Params) | ||||
| { | ||||
| 	Delegate->ProcessDelegate<UObject>(Params); | ||||
| } | ||||
|  | ||||
| bool UFScriptDelegateExporter::IsBound(FScriptDelegate* Delegate) | ||||
| { | ||||
| 	return Delegate->IsBound(); | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FScriptDelegateExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFScriptDelegateExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void BroadcastDelegate(FScriptDelegate* Delegate, void* Params); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsBound(FScriptDelegate* Delegate); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,65 @@ | ||||
| #include "FScriptMapHelperExporter.h" | ||||
|  | ||||
| void UFScriptMapHelperExporter::AddPair(FMapProperty* MapProperty, const void* Address, const void* Key, const void* Value) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	Helper.AddPair(Key, Value); | ||||
| } | ||||
|  | ||||
| void* UFScriptMapHelperExporter::FindOrAdd(FMapProperty* MapProperty, const void* Address, const void* Key) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	return Helper.FindOrAdd(Key); | ||||
| } | ||||
|  | ||||
| int UFScriptMapHelperExporter::Num(FMapProperty* MapProperty, const void* Address) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	return Helper.Num(); | ||||
| } | ||||
|  | ||||
| int UFScriptMapHelperExporter::FindMapPairIndexFromHash(FMapProperty* MapProperty, const void* Address, const void* Key) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| #if ENGINE_MINOR_VERSION >= 4 | ||||
| 	return Helper.FindMapPairIndexFromHash(Key); | ||||
| #else | ||||
| 	return Helper.FindMapIndexWithKey(Key); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| void UFScriptMapHelperExporter::RemoveIndex(FMapProperty* MapProperty, const void* Address, int Index) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	Helper.RemoveAt(Index); | ||||
| } | ||||
|  | ||||
| void UFScriptMapHelperExporter::EmptyValues(FMapProperty* MapProperty, const void* Address) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	Helper.EmptyValues(); | ||||
| } | ||||
|  | ||||
| void UFScriptMapHelperExporter::Remove(FMapProperty* MapProperty, const void* Address, const void* Key) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	Helper.RemovePair(Key); | ||||
| } | ||||
|  | ||||
| bool UFScriptMapHelperExporter::IsValidIndex(FMapProperty* MapProperty, const void* Address, int Index) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	return Helper.IsValidIndex(Index); | ||||
| } | ||||
|  | ||||
| int UFScriptMapHelperExporter::GetMaxIndex(FMapProperty* MapProperty, const void* Address) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	return Helper.GetMaxIndex(); | ||||
| } | ||||
|  | ||||
| void* UFScriptMapHelperExporter::GetPairPtr(FMapProperty* MapProperty, const void* Address, int Index) | ||||
| { | ||||
| 	FScriptMapHelper Helper(MapProperty, Address); | ||||
| 	return Helper.GetPairPtr(Index); | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FScriptMapHelperExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFScriptMapHelperExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void AddPair(FMapProperty* MapProperty, const void* Address, const void* Key, const void* Value); | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* FindOrAdd(FMapProperty* MapProperty, const void* Address, const void* Key); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int Num(FMapProperty* MapProperty, const void* Address); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int FindMapPairIndexFromHash(FMapProperty* MapProperty, const void* Address, const void* Key); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RemoveIndex(FMapProperty* MapProperty, const void* Address, int Index); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void EmptyValues(FMapProperty* MapProperty, const void* Address); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void Remove(FMapProperty* MapProperty, const void* Address, const void* Key); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsValidIndex(FMapProperty* MapProperty, const void* Address, int Index); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int GetMaxIndex(FMapProperty* MapProperty, const void* Address); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetPairPtr(FMapProperty* MapProperty, const void* Address, int Index); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,52 @@ | ||||
| #include "FScriptSetExporter.h" | ||||
|  | ||||
| bool UFScriptSetExporter::IsValidIndex(FScriptSet* ScriptSet, int32 Index) | ||||
| { | ||||
| 	return ScriptSet->IsValidIndex(Index); | ||||
| } | ||||
|  | ||||
| int UFScriptSetExporter::Num(FScriptSet* ScriptSet) | ||||
| { | ||||
| 	int Num = ScriptSet->Num(); | ||||
| 	return Num; | ||||
| } | ||||
|  | ||||
| int UFScriptSetExporter::GetMaxIndex(FScriptSet* ScriptSet) | ||||
| { | ||||
| 	return ScriptSet->GetMaxIndex(); | ||||
| } | ||||
|  | ||||
| void* UFScriptSetExporter::GetData(int Index, FScriptSet* ScriptSet, FSetProperty* Property) | ||||
| { | ||||
| 	return ScriptSet->GetData(Index, Property->SetLayout); | ||||
| } | ||||
|  | ||||
| void UFScriptSetExporter::Empty(int Slack, FScriptSet* ScriptSet, FSetProperty* Property) | ||||
| { | ||||
| 	return ScriptSet->Empty(Slack, Property->SetLayout); | ||||
| } | ||||
|  | ||||
| void UFScriptSetExporter::RemoveAt(int Index, FScriptSet* ScriptSet, FSetProperty* Property) | ||||
| { | ||||
| 	return ScriptSet->RemoveAt(Index, Property->SetLayout); | ||||
| } | ||||
|  | ||||
| int UFScriptSetExporter::AddUninitialized(FScriptSet* ScriptSet, FSetProperty* Property) | ||||
| { | ||||
| 	return ScriptSet->AddUninitialized(Property->SetLayout); | ||||
| } | ||||
|  | ||||
| void UFScriptSetExporter::Add(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element,FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn, FDestructFn DestructFn) | ||||
| { | ||||
| 	ScriptSet->Add(Element, Property->SetLayout, GetKeyHash, EqualityFn, ConstructFn, DestructFn); | ||||
| } | ||||
|  | ||||
| int32 UFScriptSetExporter::FindOrAdd(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn) | ||||
| { | ||||
| 	return ScriptSet->FindOrAdd(Element, Property->SetLayout, GetKeyHash, EqualityFn, ConstructFn); | ||||
| } | ||||
|  | ||||
| int UFScriptSetExporter::FindIndex(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn) | ||||
| { | ||||
| 	return ScriptSet->FindIndex(Element, Property->SetLayout, GetKeyHash, EqualityFn); | ||||
| } | ||||
| @ -0,0 +1,50 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FScriptSetExporter.generated.h" | ||||
|  | ||||
| using FGetKeyHash = uint32(*)(const void*); | ||||
| using FEqualityFn = bool(*)(const void*, const void*); | ||||
| using FConstructFn = void(*)(void*); | ||||
| using FDestructFn = void(*)(void*); | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFScriptSetExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
| 	 | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static bool IsValidIndex(FScriptSet* ScriptSet, int32 Index); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int Num(FScriptSet* ScriptSet); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int GetMaxIndex(FScriptSet* ScriptSet); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetData(int Index, FScriptSet* ScriptSet, FSetProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void Empty(int Slack, FScriptSet* ScriptSet, FSetProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void RemoveAt(int Index, FScriptSet* ScriptSet, FSetProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int AddUninitialized(FScriptSet* ScriptSet, FSetProperty* Property); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void Add(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn, FDestructFn DestructFn); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int32 FindOrAdd(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn); | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static int FindIndex(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn); | ||||
| 	 | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,6 @@ | ||||
| #include "FSetPropertyExporter.h" | ||||
|  | ||||
| void* UFSetPropertyExporter::GetElement(FSetProperty* Property) | ||||
| { | ||||
| 	return Property->ElementProp; | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FSetPropertyExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFSetPropertyExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
| public: | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* GetElement(FSetProperty* Property); | ||||
| }; | ||||
| @ -0,0 +1,13 @@ | ||||
| #include "FSoftObjectPtrExporter.h" | ||||
| #include "UnrealSharpCore/CSManager.h" | ||||
|  | ||||
| void* UFSoftObjectPtrExporter::LoadSynchronous(const TSoftObjectPtr<UObject>* SoftObjectPtr) | ||||
| { | ||||
| 	if (SoftObjectPtr->IsNull()) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	 | ||||
| 	UObject* LoadedObject = SoftObjectPtr->LoadSynchronous(); | ||||
| 	return UCSManager::Get().FindManagedObject(LoadedObject); | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FSoftObjectPtrExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFSoftObjectPtrExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void* LoadSynchronous(const TSoftObjectPtr<UObject>* SoftObjectPtr); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,6 @@ | ||||
| #include "FStringExporter.h" | ||||
|  | ||||
| void UFStringExporter::MarshalToNativeString(FString* String, TCHAR* ManagedString) | ||||
| { | ||||
| 	*String = ManagedString; | ||||
| } | ||||
| @ -0,0 +1,17 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "FStringExporter.generated.h" | ||||
|  | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFStringExporter : public UObject | ||||
| { | ||||
| 	GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	UNREALSHARP_FUNCTION() | ||||
| 	static void MarshalToNativeString(FString* String, TCHAR* ManagedString); | ||||
| 	 | ||||
| }; | ||||
| @ -0,0 +1,9 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
|  | ||||
| #include "FSubsystemCollectionBaseRefExporter.h" | ||||
|  | ||||
| USubsystem* UFSubsystemCollectionBaseRefExporter::InitializeDependency(FSubsystemCollectionBase* Collection, UClass* SubsystemClass) | ||||
| { | ||||
|     return Collection->InitializeDependency(SubsystemClass); | ||||
| } | ||||
| @ -0,0 +1,21 @@ | ||||
| // Fill out your copyright notice in the Description page of Project Settings. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "CoreMinimal.h" | ||||
| #include "CSBindsManager.h" | ||||
| #include "UObject/Object.h" | ||||
| #include "FSubsystemCollectionBaseRefExporter.generated.h" | ||||
|  | ||||
| /** | ||||
|  * | ||||
|  */ | ||||
| UCLASS() | ||||
| class UNREALSHARPCORE_API UFSubsystemCollectionBaseRefExporter : public UObject | ||||
| { | ||||
|     GENERATED_BODY() | ||||
|  | ||||
| public: | ||||
|     UNREALSHARP_FUNCTION() | ||||
|     static USubsystem* InitializeDependency(FSubsystemCollectionBase* Collection, UClass* SubsystemClass); | ||||
| }; | ||||
| @ -0,0 +1,66 @@ | ||||
| #include "FTextExporter.h" | ||||
|  | ||||
| const TCHAR* UFTextExporter::ToString(FText* Text) | ||||
| { | ||||
| 	if (!Text) | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	 | ||||
| 	return *Text->ToString(); | ||||
| } | ||||
|  | ||||
| void UFTextExporter::ToStringView(FText* Text, const TCHAR*& OutString, int32& OutLength) | ||||
| { | ||||
|     if (!Text) | ||||
|     { | ||||
|         OutString = nullptr; | ||||
|         OutLength = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const FString& AsString = Text->ToString(); | ||||
|     OutString = *AsString; | ||||
|     OutLength = AsString.Len(); | ||||
| } | ||||
|  | ||||
| void UFTextExporter::FromString(FText* Text, const char* String) | ||||
| { | ||||
| 	if (!Text) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	*Text = Text->FromString(String); | ||||
| } | ||||
|  | ||||
| void UFTextExporter::FromStringView(FText* Text, const TCHAR* String, int32 Length) | ||||
| { | ||||
|     if (!Text) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     *Text = Text->FromStringView(FStringView(String, Length)); | ||||
| } | ||||
|  | ||||
| void UFTextExporter::FromName(FText* Text, FName Name) | ||||
| { | ||||
| 	if (!Text) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	*Text = Text->FromName(Name); | ||||
| } | ||||
|  | ||||
| void UFTextExporter::CreateEmptyText(FText* Text) | ||||
| { | ||||
| 	if (!Text) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	*Text = FText::GetEmpty(); | ||||
| } | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user