Lua向C#逻辑迁移 一期 #13

将整个插件代码上传
This commit is contained in:
2025-10-26 21:48:39 +08:00
parent 56994b3927
commit 648386cd73
785 changed files with 53683 additions and 2 deletions

View File

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

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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)

View File

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

View File

@ -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();
};

View File

@ -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();
};

View File

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

View File

@ -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");
}
}

View File

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

View File

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

View File

@ -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)

View File

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

View File

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

View File

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

View File

@ -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"
}
);
}
}

View File

@ -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

View File

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

View File

@ -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

View File

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

View File

@ -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");
}
}

View File

@ -0,0 +1,17 @@
#include "UnrealSharpBlueprint.h"
#define LOCTEXT_NAMESPACE "FUnrealSharpBlueprintModule"
void FUnrealSharpBlueprintModule::StartupModule()
{
}
void FUnrealSharpBlueprintModule::ShutdownModule()
{
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FUnrealSharpBlueprintModule, UnrealSharpBlueprint)

View File

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

View File

@ -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();
}
}

View File

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

View File

@ -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

View File

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

View File

@ -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"
}
);
}
}

View File

@ -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)

View File

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

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

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

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

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

View File

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

View File

@ -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();
}
}

View File

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

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

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

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

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

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

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

@ -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();
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
#include "FCSManagedCallbacksExporter.h"
#include "CSManagedCallbacksCache.h"
FCSManagedCallbacks::FManagedCallbacks* UFCSManagedCallbacksExporter::GetManagedCallbacks()
{
return &FCSManagedCallbacks::ManagedCallbacks;
}

View File

@ -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();
};

View File

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

View File

@ -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();
};

View File

@ -0,0 +1,6 @@
#include "FCSTypeRegistryExporter.h"
void UFCSTypeRegistryExporter::RegisterClassToFilePath(const UTF16CHAR* ClassName, const UTF16CHAR* FilePath)
{
//FCSTypeRegistry::Get().RegisterClassToFilePath(ClassName, FilePath);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

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

View File

@ -0,0 +1,11 @@
#include "FMapPropertyExporter.h"
void* UFMapPropertyExporter::GetKey(FMapProperty* MapProperty)
{
return MapProperty->KeyProp;
}
void* UFMapPropertyExporter::GetValue(FMapProperty* MapProperty)
{
return MapProperty->ValueProp;
}

View File

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

View File

@ -0,0 +1,6 @@
#include "FMatrixExporter.h"
void UFMatrixExporter::FromRotator(FMatrix* Matrix, const FRotator Rotator)
{
*Matrix = Rotator.Quaternion().ToMatrix();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
#include "FRotatorExporter.h"
void UFRotatorExporter::FromMatrix(FRotator* Rotator, const FMatrix& Matrix)
{
*Rotator = Matrix.Rotator();
}

View File

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

View File

@ -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();
}

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
#include "FSetPropertyExporter.h"
void* UFSetPropertyExporter::GetElement(FSetProperty* Property)
{
return Property->ElementProp;
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
#include "FStringExporter.h"
void UFStringExporter::MarshalToNativeString(FString* String, TCHAR* ManagedString)
{
*String = ManagedString;
}

View File

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

View File

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

View File

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

View File

@ -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