@ -0,0 +1,49 @@
|
||||
#include "CSAsyncActionBase.h"
|
||||
#include "UnrealSharpAsync.h"
|
||||
|
||||
void UCSAsyncActionBase::Destroy()
|
||||
{
|
||||
if (UGameInstance* GameInstance = GetWorld()->GetGameInstance())
|
||||
{
|
||||
GameInstance->UnregisterReferencedObject(this);
|
||||
}
|
||||
|
||||
ManagedCallback.Dispose();
|
||||
MarkAsGarbage();
|
||||
}
|
||||
|
||||
void UCSAsyncActionBase::InvokeManagedCallback(bool bDispose)
|
||||
{
|
||||
InvokeManagedCallback(this, bDispose);
|
||||
}
|
||||
|
||||
void UCSAsyncActionBase::InvokeManagedCallback(UObject* WorldContextObject, bool bDispose)
|
||||
{
|
||||
ManagedCallback.Invoke(WorldContextObject, bDispose);
|
||||
|
||||
if (bDispose)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void UCSAsyncActionBase::InitializeManagedCallback(FGCHandleIntPtr Callback)
|
||||
{
|
||||
ManagedCallback = FGCHandle(Callback, GCHandleType::WeakHandle);
|
||||
|
||||
if (UGameInstance* GameInstance = GetWorld()->GetGameInstance())
|
||||
{
|
||||
GameInstance->RegisterReferencedObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
void UUCSAsyncBaseExporter::InitializeAsyncObject(UCSAsyncActionBase* AsyncAction, FGCHandleIntPtr Callback)
|
||||
{
|
||||
if (!IsValid(AsyncAction))
|
||||
{
|
||||
UE_LOG(LogUnrealSharpAsync, Warning, TEXT("UUCSAsyncBaseExporter::InitializeAsyncObject: AsyncAction is null"));
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncAction->InitializeManagedCallback(Callback);
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
#include "CSAsyncLoadPrimaryDataAssets.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
|
||||
void UCSAsyncLoadPrimaryDataAssets::LoadPrimaryDataAssets(const TArray<FPrimaryAssetId>& AssetIds, const TArray<FName>& AssetBundles)
|
||||
{
|
||||
UAssetManager& AssetManager = UAssetManager::Get();
|
||||
AssetManager.LoadPrimaryAssets(AssetIds, AssetBundles, FStreamableDelegate::CreateUObject(this, &UCSAsyncLoadPrimaryDataAssets::OnPrimaryDataAssetsLoaded));
|
||||
}
|
||||
|
||||
void UCSAsyncLoadPrimaryDataAssets::OnPrimaryDataAssetsLoaded()
|
||||
{
|
||||
InvokeManagedCallback();
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
#include "CSAsyncLoadSoftObjectPtr.h"
|
||||
#include "Engine/AssetManager.h"
|
||||
#include "Engine/StreamableManager.h"
|
||||
|
||||
void UCSAsyncLoadSoftPtr::LoadSoftObjectPaths(const TArray<FSoftObjectPath>& SoftObjectPtr)
|
||||
{
|
||||
UAssetManager::Get().GetStreamableManager().RequestAsyncLoad(SoftObjectPtr,
|
||||
FStreamableDelegate::CreateUObject(this, &UCSAsyncLoadSoftPtr::OnAsyncLoadComplete));
|
||||
}
|
||||
|
||||
void UCSAsyncLoadSoftPtr::OnAsyncLoadComplete()
|
||||
{
|
||||
InvokeManagedCallback();
|
||||
}
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
#include "UnrealSharpAsync.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FUnrealSharpAsyncModule"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogUnrealSharpAsync);
|
||||
|
||||
void FUnrealSharpAsyncModule::StartupModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FUnrealSharpAsyncModule::ShutdownModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FUnrealSharpAsyncModule, UnrealSharpAsync)
|
||||
@ -0,0 +1,36 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSManagedDelegate.h"
|
||||
#include "CSManagedGCHandle.h"
|
||||
#include "UnrealSharpBinds/Public/CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "CSAsyncActionBase.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPASYNC_API UCSAsyncActionBase : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(meta = (ScriptMethod))
|
||||
void Destroy();
|
||||
protected:
|
||||
friend class UUCSAsyncBaseExporter;
|
||||
|
||||
void InvokeManagedCallback(bool bDispose = true);
|
||||
void InvokeManagedCallback(UObject* WorldContextObject, bool bDispose = true);
|
||||
void InitializeManagedCallback(FGCHandleIntPtr Callback);
|
||||
|
||||
FCSManagedDelegate ManagedCallback;
|
||||
};
|
||||
|
||||
UCLASS(meta = (InternalType))
|
||||
class UUCSAsyncBaseExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void InitializeAsyncObject(UCSAsyncActionBase* AsyncAction, FGCHandleIntPtr Callback);
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSAsyncActionBase.h"
|
||||
#include "CSAsyncLoadPrimaryDataAssets.generated.h"
|
||||
|
||||
UCLASS(meta = (InternalType))
|
||||
class UCSAsyncLoadPrimaryDataAssets : public UCSAsyncActionBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(meta =(ScriptMethod))
|
||||
void LoadPrimaryDataAssets(const TArray<FPrimaryAssetId>& AssetIds, const TArray<FName>& AssetBundles);
|
||||
private:
|
||||
void OnPrimaryDataAssetsLoaded();
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSAsyncActionBase.h"
|
||||
#include "CSAsyncLoadSoftObjectPtr.generated.h"
|
||||
|
||||
UCLASS(meta = (InternalType))
|
||||
class UCSAsyncLoadSoftPtr : public UCSAsyncActionBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UFUNCTION(meta = (ScriptMethod))
|
||||
void LoadSoftObjectPaths(const TArray<FSoftObjectPath>& SoftObjectPtr);
|
||||
protected:
|
||||
void OnAsyncLoadComplete();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpAsync, Log, All);
|
||||
|
||||
class FUnrealSharpAsyncModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class UnrealSharpAsync : ModuleRules
|
||||
{
|
||||
public UnrealSharpAsync(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"UnrealSharpBinds",
|
||||
"UnrealSharpCore"
|
||||
}
|
||||
);
|
||||
|
||||
PublicDefinitions.Add("ForceAsEngineGlue=1");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
#include "CSBindsManager.h"
|
||||
#include "UnrealSharpBinds.h"
|
||||
|
||||
FCSBindsManager* FCSBindsManager::BindsManagerInstance = nullptr;
|
||||
|
||||
FCSBindsManager* FCSBindsManager::Get()
|
||||
{
|
||||
if (!BindsManagerInstance)
|
||||
{
|
||||
BindsManagerInstance = new FCSBindsManager();
|
||||
}
|
||||
|
||||
return BindsManagerInstance;
|
||||
}
|
||||
|
||||
void FCSBindsManager::RegisterExportedFunction(const FName& ClassName, const FCSExportedFunction& ExportedFunction)
|
||||
{
|
||||
FCSBindsManager* Instance = Get();
|
||||
TArray<FCSExportedFunction>& ExportedFunctions = Instance->ExportedFunctionsMap.FindOrAdd(ClassName);
|
||||
ExportedFunctions.Add(ExportedFunction);
|
||||
}
|
||||
|
||||
void* FCSBindsManager::GetBoundFunction(const TCHAR* InOuterName, const TCHAR* InFunctionName, int32 ManagedFunctionSize)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSBindsManager::GetBoundFunction);
|
||||
|
||||
FCSBindsManager* Instance = Get();
|
||||
FName ManagedOuterName = FName(InOuterName);
|
||||
FName ManagedFunctionName = FName(InFunctionName);
|
||||
|
||||
TArray<FCSExportedFunction>* ExportedFunctions = Instance->ExportedFunctionsMap.Find(ManagedOuterName);
|
||||
|
||||
if (!ExportedFunctions)
|
||||
{
|
||||
UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: No exported functions found for %s"), InOuterName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (FCSExportedFunction& NativeFunction : *ExportedFunctions)
|
||||
{
|
||||
if (NativeFunction.Name != ManagedFunctionName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NativeFunction.Size != ManagedFunctionSize)
|
||||
{
|
||||
UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: Function size mismatch for %s::%s."), InOuterName, InFunctionName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NativeFunction.FunctionPointer;
|
||||
}
|
||||
|
||||
UE_LOG(LogUnrealSharpBinds, Error, TEXT("Failed to get BoundNativeFunction: No function found for %s.%s"), *ManagedOuterName.ToString(), *ManagedFunctionName.ToString());
|
||||
return nullptr;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
#include "CSExportedFunction.h"
|
||||
|
||||
#include "CSBindsManager.h"
|
||||
|
||||
FCSExportedFunction::FCSExportedFunction(const FName& OuterName, const FName& Name, void* InFunctionPointer, int32 InSize):
|
||||
Name(Name),
|
||||
FunctionPointer(InFunctionPointer),
|
||||
Size(InSize)
|
||||
{
|
||||
FCSBindsManager::RegisterExportedFunction(OuterName, *this);
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
#include "UnrealSharpBinds.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FUnrealSharpBindsModule"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogUnrealSharpBinds);
|
||||
|
||||
void FUnrealSharpBindsModule::StartupModule()
|
||||
{
|
||||
}
|
||||
|
||||
void FUnrealSharpBindsModule::ShutdownModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FUnrealSharpBindsModule, UnrealSharpBinds)
|
||||
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "CSExportedFunction.h"
|
||||
|
||||
// Native bound function. If you want to bind a function to C#, use this macro.
|
||||
// The managed delegate signature must match the native function signature + outer name, and all params need to be blittable.
|
||||
#define UNREALSHARP_FUNCTION()
|
||||
|
||||
class FCSBindsManager
|
||||
{
|
||||
public:
|
||||
|
||||
static FCSBindsManager* Get();
|
||||
|
||||
UNREALSHARPBINDS_API static void RegisterExportedFunction(const FName& ClassName, const FCSExportedFunction& ExportedFunction);
|
||||
|
||||
UNREALSHARPBINDS_API static void* GetBoundFunction(const TCHAR* InOuterName, const TCHAR* InFunctionName, int32 ManagedFunctionSize);
|
||||
|
||||
private:
|
||||
FCSBindsManager() = default;
|
||||
static FCSBindsManager* BindsManagerInstance;
|
||||
TMap<FName, TArray<FCSExportedFunction>> ExportedFunctionsMap;
|
||||
};
|
||||
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Thin wrapper around sizeof(T) used for getting the size of a function's arguments.
|
||||
* @tparam T The type we want the size of
|
||||
*/
|
||||
template <typename T>
|
||||
struct TArgSize
|
||||
{
|
||||
constexpr static size_t Size = sizeof(T);
|
||||
};
|
||||
|
||||
/**
|
||||
* Specialization for reference qualified types so we can get the size of the pointer instead of the object itself.
|
||||
* @tparam T The type we want the size of
|
||||
*/
|
||||
template <typename T>
|
||||
struct TArgSize<T&>
|
||||
{
|
||||
constexpr static size_t Size = sizeof(T*);
|
||||
};
|
||||
|
||||
/**
|
||||
* Constant expression for the size of an argument
|
||||
* @tparam T The type we want the size of
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr size_t ArgSize = TArgSize<T>::Size;
|
||||
|
||||
template <typename ReturnType, typename... Args>
|
||||
constexpr size_t GetFunctionSize(ReturnType (*)(Args...))
|
||||
{
|
||||
if constexpr (std::is_void_v<ReturnType>)
|
||||
{
|
||||
return (ArgSize<Args> + ... + 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return ArgSize<ReturnType> + (ArgSize<Args> + ... + 0);
|
||||
}
|
||||
}
|
||||
|
||||
struct UNREALSHARPBINDS_API FCSExportedFunction
|
||||
{
|
||||
FName Name;
|
||||
void* FunctionPointer;
|
||||
int32 Size;
|
||||
|
||||
FCSExportedFunction(const FName& OuterName, const FName& Name, void* InFunctionPointer, int32 InSize);
|
||||
};
|
||||
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpBinds, Log, All);
|
||||
|
||||
class FUnrealSharpBindsModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
// IModuleInterface interface
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
// End of IModuleInterface interface
|
||||
};
|
||||
@ -0,0 +1,26 @@
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class UnrealSharpBinds : ModuleRules
|
||||
{
|
||||
public UnrealSharpBinds(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
#include "K2Node_CSAsyncAction.h"
|
||||
|
||||
#include "BlueprintActionDatabaseRegistrar.h"
|
||||
#include "BlueprintFunctionNodeSpawner.h"
|
||||
#include "BlueprintNodeSpawner.h"
|
||||
#include "Delegates/Delegate.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "Extensions/BlueprintActions/CSBlueprintAsyncActionBase.h"
|
||||
#include "HAL/Platform.h"
|
||||
#include "Misc/AssertionMacros.h"
|
||||
#include "Templates/Casts.h"
|
||||
#include "Templates/SubclassOf.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "UObject/Class.h"
|
||||
#include "UObject/Field.h"
|
||||
#include "UObject/NameTypes.h"
|
||||
#include "UObject/ObjectPtr.h"
|
||||
#include "UObject/UnrealType.h"
|
||||
#include "UObject/WeakObjectPtrTemplates.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "K2Node"
|
||||
|
||||
UK2Node_CSAsyncAction::UK2Node_CSAsyncAction()
|
||||
{
|
||||
ProxyActivateFunctionName = GET_FUNCTION_NAME_CHECKED(UCSBlueprintAsyncActionBase, Activate);
|
||||
}
|
||||
|
||||
void UK2Node_CSAsyncAction::SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr)
|
||||
{
|
||||
UK2Node_CSAsyncAction* AsyncTaskNode = CastChecked<UK2Node_CSAsyncAction>(NewNode);
|
||||
if (FunctionPtr.IsValid())
|
||||
{
|
||||
UFunction* Func = FunctionPtr.Get();
|
||||
FObjectProperty* ReturnProp = CastFieldChecked<FObjectProperty>(Func->GetReturnProperty());
|
||||
|
||||
AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
|
||||
AsyncTaskNode->ProxyFactoryClass = Func->GetOuterUClass();
|
||||
AsyncTaskNode->ProxyClass = ReturnProp->PropertyClass;
|
||||
}
|
||||
}
|
||||
|
||||
void UK2Node_CSAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
||||
{
|
||||
struct GetMenuActions_Utils
|
||||
{
|
||||
static bool IsFactoryMethod(const UFunction* Function, const UClass* InTargetType)
|
||||
{
|
||||
if (!Function->HasAnyFunctionFlags(FUNC_Static))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Function->GetOwnerClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists))
|
||||
{
|
||||
FObjectProperty* ReturnProperty = CastField<FObjectProperty>(Function->GetReturnProperty());
|
||||
// see if the function is a static factory method
|
||||
bool const bIsFactoryMethod = (ReturnProperty != nullptr) && (ReturnProperty->PropertyClass != nullptr) &&
|
||||
ReturnProperty->PropertyClass->IsChildOf(InTargetType);
|
||||
|
||||
return bIsFactoryMethod;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static UBlueprintNodeSpawner* MakeAction(UClass* NodeClass, const UFunction* FactoryFunc)
|
||||
{
|
||||
UClass* FactoryClass = FactoryFunc ? FactoryFunc->GetOwnerClass() : nullptr;
|
||||
if (FactoryClass && FactoryClass->HasMetaData(TEXT("HasDedicatedAsyncNode")))
|
||||
{
|
||||
// Wants to use a more specific blueprint node to handle the async action
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc);
|
||||
check(NodeSpawner != nullptr);
|
||||
NodeSpawner->NodeClass = NodeClass;
|
||||
|
||||
TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc));
|
||||
NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(SetNodeFunc, FunctionPtr);
|
||||
|
||||
return NodeSpawner;
|
||||
}
|
||||
};
|
||||
|
||||
UClass* NodeClass = GetClass();
|
||||
UClass* TargetType = UCSBlueprintAsyncActionBase::StaticClass();
|
||||
|
||||
for (TObjectIterator<UCSClass> ClassIt; ClassIt; ++ClassIt)
|
||||
{
|
||||
UCSClass* Class = *ClassIt;
|
||||
if (Class->HasAnyClassFlags(CLASS_Abstract) || !Class->IsChildOf(TargetType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
|
||||
{
|
||||
UFunction* Function = *FuncIt;
|
||||
if (!GetMenuActions_Utils::IsFactoryMethod(Function, TargetType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (UBlueprintNodeSpawner* NewAction = GetMenuActions_Utils::MakeAction(NodeClass, Function))
|
||||
{
|
||||
ActionRegistrar.AddBlueprintAction(Class, NewAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UK2Node_CSAsyncAction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
||||
{
|
||||
if (ProxyClass->bLayoutChanging)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Super::ExpandNode(CompilerContext, SourceGraph);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -0,0 +1,30 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "K2Node_BaseAsyncTask.h"
|
||||
#include "UObject/ObjectMacros.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
|
||||
#include "K2Node_CSAsyncAction.generated.h"
|
||||
|
||||
class FBlueprintActionDatabaseRegistrar;
|
||||
class UObject;
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPBLUEPRINT_API UK2Node_CSAsyncAction : public UK2Node_BaseAsyncTask
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UK2Node_CSAsyncAction();
|
||||
|
||||
static void SetNodeFunc(UEdGraphNode* NewNode, bool, TWeakObjectPtr<UFunction> FunctionPtr);
|
||||
|
||||
// UK2Node interface
|
||||
virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override;
|
||||
virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override;
|
||||
// End of UK2Node interface
|
||||
};
|
||||
@ -0,0 +1,124 @@
|
||||
#include "K2Node_CSCancellableAsyncAction.h"
|
||||
|
||||
#include "BlueprintActionDatabaseRegistrar.h"
|
||||
#include "BlueprintFunctionNodeSpawner.h"
|
||||
#include "BlueprintNodeSpawner.h"
|
||||
#include "Delegates/Delegate.h"
|
||||
#include "EdGraph/EdGraphNode.h"
|
||||
#include "Extensions/BlueprintActions/CSCancellableAsyncAction.h"
|
||||
#include "HAL/Platform.h"
|
||||
#include "Misc/AssertionMacros.h"
|
||||
#include "Templates/Casts.h"
|
||||
#include "Templates/SubclassOf.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "UObject/Class.h"
|
||||
#include "UObject/Field.h"
|
||||
#include "UObject/NameTypes.h"
|
||||
#include "UObject/ObjectPtr.h"
|
||||
#include "UObject/UnrealType.h"
|
||||
#include "UObject/WeakObjectPtrTemplates.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "K2Node"
|
||||
|
||||
UK2Node_CSCancellableAsyncAction::UK2Node_CSCancellableAsyncAction()
|
||||
{
|
||||
ProxyActivateFunctionName = GET_FUNCTION_NAME_CHECKED(UCSCancellableAsyncAction, Activate);
|
||||
}
|
||||
|
||||
void UK2Node_CSCancellableAsyncAction::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
|
||||
{
|
||||
struct GetMenuActions_Utils
|
||||
{
|
||||
static bool IsFactoryMethod(const UFunction* Function, const UClass* InTargetType)
|
||||
{
|
||||
if (!Function->HasAnyFunctionFlags(FUNC_Static))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Function->GetOwnerClass()->HasAnyClassFlags(CLASS_Deprecated | CLASS_NewerVersionExists))
|
||||
{
|
||||
FObjectProperty* ReturnProperty = CastField<FObjectProperty>(Function->GetReturnProperty());
|
||||
// see if the function is a static factory method
|
||||
bool const bIsFactoryMethod = (ReturnProperty != nullptr) && (ReturnProperty->PropertyClass != nullptr) &&
|
||||
ReturnProperty->PropertyClass->IsChildOf(InTargetType);
|
||||
|
||||
return bIsFactoryMethod;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetNodeFunc(UEdGraphNode* NewNode, bool /*bIsTemplateNode*/, TWeakObjectPtr<UFunction> FunctionPtr)
|
||||
{
|
||||
UK2Node_CSCancellableAsyncAction* AsyncTaskNode = CastChecked<UK2Node_CSCancellableAsyncAction>(NewNode);
|
||||
if (FunctionPtr.IsValid())
|
||||
{
|
||||
UFunction* Func = FunctionPtr.Get();
|
||||
FObjectProperty* ReturnProp = CastFieldChecked<FObjectProperty>(Func->GetReturnProperty());
|
||||
|
||||
AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
|
||||
AsyncTaskNode->ProxyFactoryClass = Func->GetOuterUClass();
|
||||
AsyncTaskNode->ProxyClass = ReturnProp->PropertyClass;
|
||||
}
|
||||
}
|
||||
|
||||
static UBlueprintNodeSpawner* MakeAction(UClass* NodeClass, const UFunction* FactoryFunc)
|
||||
{
|
||||
UClass* FactoryClass = FactoryFunc ? FactoryFunc->GetOwnerClass() : nullptr;
|
||||
if (FactoryClass && FactoryClass->HasMetaData(TEXT("HasDedicatedAsyncNode")))
|
||||
{
|
||||
// Wants to use a more specific blueprint node to handle the async action
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(FactoryFunc);
|
||||
check(NodeSpawner != nullptr);
|
||||
NodeSpawner->NodeClass = NodeClass;
|
||||
|
||||
TWeakObjectPtr<UFunction> FunctionPtr = MakeWeakObjectPtr(const_cast<UFunction*>(FactoryFunc));
|
||||
NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(GetMenuActions_Utils::SetNodeFunc, FunctionPtr);
|
||||
|
||||
return NodeSpawner;
|
||||
}
|
||||
};
|
||||
|
||||
UClass* NodeClass = GetClass();
|
||||
UClass* TargetType = UCSCancellableAsyncAction::StaticClass();
|
||||
|
||||
for (TObjectIterator<UCSClass> ClassIt; ClassIt; ++ClassIt)
|
||||
{
|
||||
UCSClass* Class = *ClassIt;
|
||||
if (Class->HasAnyClassFlags(CLASS_Abstract) || !Class->IsChildOf(TargetType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
|
||||
{
|
||||
UFunction* Function = *FuncIt;
|
||||
if (!GetMenuActions_Utils::IsFactoryMethod(Function, TargetType))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (UBlueprintNodeSpawner* NewAction = GetMenuActions_Utils::MakeAction(NodeClass, Function))
|
||||
{
|
||||
ActionRegistrar.AddBlueprintAction(Class, NewAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UK2Node_CSCancellableAsyncAction::ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph)
|
||||
{
|
||||
if (ProxyClass->bLayoutChanging)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Super::ExpandNode(CompilerContext, SourceGraph);
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -0,0 +1,28 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "K2Node_CSAsyncAction.h"
|
||||
#include "UObject/ObjectMacros.h"
|
||||
#include "UObject/UObjectGlobals.h"
|
||||
|
||||
#include "K2Node_CSCancellableAsyncAction.generated.h"
|
||||
|
||||
class FBlueprintActionDatabaseRegistrar;
|
||||
class UObject;
|
||||
|
||||
UCLASS()
|
||||
class UK2Node_CSCancellableAsyncAction : public UK2Node_CSAsyncAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UK2Node_CSCancellableAsyncAction();
|
||||
|
||||
// UK2Node interface
|
||||
virtual void GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const override;
|
||||
virtual void ExpandNode(class FKismetCompilerContext& CompilerContext, UEdGraph* SourceGraph) override;
|
||||
// End of UK2Node interface
|
||||
};
|
||||
@ -0,0 +1,28 @@
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class UnrealSharpBlueprint : ModuleRules
|
||||
{
|
||||
public UnrealSharpBlueprint(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"UnrealSharpCore",
|
||||
"BlueprintGraph"
|
||||
}
|
||||
);
|
||||
|
||||
PublicDefinitions.Add("SkipGlueGeneration");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
#include "UnrealSharpBlueprint.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FUnrealSharpBlueprintModule"
|
||||
|
||||
void FUnrealSharpBlueprintModule::StartupModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FUnrealSharpBlueprintModule::ShutdownModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FUnrealSharpBlueprintModule, UnrealSharpBlueprint)
|
||||
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class FUnrealSharpBlueprintModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
// IModuleInterface interface begin
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
// End
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
#include "CSBlueprintCompiler.h"
|
||||
#include "CSCompilerContext.h"
|
||||
#include "TypeGenerator/CSBlueprint.h"
|
||||
|
||||
bool FCSBlueprintCompiler::CanCompile(const UBlueprint* Blueprint)
|
||||
{
|
||||
return Blueprint->IsA<UCSBlueprint>();
|
||||
}
|
||||
|
||||
void FCSBlueprintCompiler::Compile(UBlueprint* Blueprint, const FKismetCompilerOptions& CompileOptions, FCompilerResultsLog& Results)
|
||||
{
|
||||
if (UCSBlueprint* CSBlueprint = CastChecked<UCSBlueprint>(Blueprint))
|
||||
{
|
||||
FCSCompilerContext Compiler(CSBlueprint, Results, CompileOptions);
|
||||
Compiler.Compile();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "KismetCompilerModule.h"
|
||||
|
||||
class UCSClass;
|
||||
class UCSBlueprint;
|
||||
|
||||
class FCSBlueprintCompiler : public IBlueprintCompiler
|
||||
{
|
||||
public:
|
||||
// IBlueprintCompiler interface
|
||||
virtual bool CanCompile(const UBlueprint* Blueprint) override;
|
||||
virtual void Compile(UBlueprint* Blueprint, const FKismetCompilerOptions& CompileOptions, FCompilerResultsLog& Results) override;
|
||||
// End of IBlueprintCompiler interface
|
||||
};
|
||||
@ -0,0 +1,289 @@
|
||||
#include "CSCompilerContext.h"
|
||||
|
||||
#include "BlueprintActionDatabase.h"
|
||||
#include "ISettingsModule.h"
|
||||
#include "BehaviorTree/Tasks/BTTask_BlueprintBase.h"
|
||||
#include "Blueprint/StateTreeTaskBlueprintBase.h"
|
||||
#include "Engine/SCS_Node.h"
|
||||
#include "Engine/SimpleConstructionScript.h"
|
||||
#include "TypeGenerator/CSBlueprint.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "TypeGenerator/CSSkeletonClass.h"
|
||||
#include "TypeGenerator/Factories/CSFunctionFactory.h"
|
||||
#include "TypeGenerator/Factories/CSPropertyFactory.h"
|
||||
#include "TypeGenerator/Factories/PropertyGenerators/CSPropertyGenerator.h"
|
||||
#include "TypeGenerator/Register/CSGeneratedClassBuilder.h"
|
||||
#include "TypeGenerator/Register/CSMetaDataUtils.h"
|
||||
#include "TypeGenerator/Register/CSSimpleConstructionScriptBuilder.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSClassMetaData.h"
|
||||
#include "TypeGenerator/Register/TypeInfo/CSClassInfo.h"
|
||||
#include "UnrealSharpEditor/CSUnrealSharpEditorSettings.h"
|
||||
#include "UnrealSharpUtilities/UnrealSharpUtils.h"
|
||||
#include "Utils/CSClassUtilities.h"
|
||||
|
||||
FCSCompilerContext::FCSCompilerContext(UCSBlueprint* Blueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompilerOptions):
|
||||
FKismetCompilerContext(Blueprint, InMessageLog, InCompilerOptions)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FCSCompilerContext::FinishCompilingClass(UClass* Class)
|
||||
{
|
||||
bool bIsSkeletonClass = FCSClassUtilities::IsSkeletonType(Class);
|
||||
|
||||
if (!bIsSkeletonClass)
|
||||
{
|
||||
// The skeleton class shouldn't be using the managed constructor since it's not tied to an assembly
|
||||
Class->ClassConstructor = &UCSGeneratedClassBuilder::ManagedObjectConstructor;
|
||||
}
|
||||
|
||||
Super::FinishCompilingClass(Class);
|
||||
|
||||
TSharedPtr<FCSClassMetaData> TypeMetaData = GetClassInfo()->GetTypeMetaData<FCSClassMetaData>();
|
||||
|
||||
// Super call overrides the class flags, so we need to set after that
|
||||
Class->ClassFlags |= TypeMetaData->ClassFlags;
|
||||
|
||||
if (NeedsToFakeNativeClass(Class) && !bIsSkeletonClass)
|
||||
{
|
||||
// There are systems in Unreal (BehaviorTree, StateTree) which uses the AssetRegistry to find BP classes, since our C# classes are not assets,
|
||||
// we need to fake that they're native classes in editor in order to be able to find them.
|
||||
|
||||
// The functions that are used to find classes are:
|
||||
// FGraphNodeClassHelper::BuildClassGraph()
|
||||
// FStateTreeNodeClassCache::CacheClasses()
|
||||
Class->ClassFlags |= CLASS_Native;
|
||||
}
|
||||
|
||||
UCSGeneratedClassBuilder::SetConfigName(Class, TypeMetaData);
|
||||
TryInitializeAsDeveloperSettings(Class);
|
||||
ApplyMetaData();
|
||||
}
|
||||
|
||||
void FCSCompilerContext::OnPostCDOCompiled(const UObject::FPostCDOCompiledContext& Context)
|
||||
{
|
||||
FKismetCompilerContext::OnPostCDOCompiled(Context);
|
||||
|
||||
UCSGeneratedClassBuilder::SetupDefaultTickSettings(NewClass->GetDefaultObject(), NewClass);
|
||||
|
||||
UCSClass* Class = GetMainClass();
|
||||
if (Class == NewClass)
|
||||
{
|
||||
UCSGeneratedClassBuilder::TryRegisterDynamicSubsystem(Class);
|
||||
|
||||
if (GEditor)
|
||||
{
|
||||
FBlueprintActionDatabase::Get().RefreshClassActions(Class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FCSCompilerContext::CreateClassVariablesFromBlueprint()
|
||||
{
|
||||
TSharedPtr<FCSClassInfo> ClassInfo = GetMainClass()->GetManagedTypeInfo<FCSClassInfo>();
|
||||
const TArray<FCSPropertyMetaData>& Properties = ClassInfo->GetTypeMetaData<FCSClassMetaData>()->Properties;
|
||||
|
||||
NewClass->PropertyGuids.Empty(Properties.Num());
|
||||
TryValidateSimpleConstructionScript(ClassInfo);
|
||||
|
||||
FCSPropertyFactory::CreateAndAssignProperties(NewClass, Properties, [this](const FProperty* NewProperty)
|
||||
{
|
||||
FName PropertyName = NewProperty->GetFName();
|
||||
FGuid PropertyGuid = FCSUnrealSharpUtils::ConstructGUIDFromName(PropertyName);
|
||||
NewClass->PropertyGuids.Add(PropertyName, PropertyGuid);
|
||||
});
|
||||
|
||||
// Create dummy variables for the blueprint.
|
||||
// They should not get compiled, just there for metadata for different Unreal modules.
|
||||
CreateDummyBlueprintVariables(Properties);
|
||||
}
|
||||
|
||||
void FCSCompilerContext::CleanAndSanitizeClass(UBlueprintGeneratedClass* ClassToClean, UObject*& InOldCDO)
|
||||
{
|
||||
FKismetCompilerContext::CleanAndSanitizeClass(ClassToClean, InOldCDO);
|
||||
NewClass->FieldNotifies.Reset();
|
||||
|
||||
TryDeinitializeAsDeveloperSettings(InOldCDO);
|
||||
|
||||
// Too late to generate functions in CreateFunctionList for child blueprints
|
||||
GenerateFunctions();
|
||||
}
|
||||
|
||||
void FCSCompilerContext::SpawnNewClass(const FString& NewClassName)
|
||||
{
|
||||
UCSClass* MainClass = GetMainClass();
|
||||
UCSSkeletonClass* NewSkeletonClass = NewObject<UCSSkeletonClass>(Blueprint->GetOutermost(), FName(*NewClassName), RF_Public | RF_Transactional);
|
||||
NewSkeletonClass->SetGeneratedClass(MainClass);
|
||||
NewClass = NewSkeletonClass;
|
||||
|
||||
// Skeleton class doesn't generate functions on the first pass.
|
||||
// It's done in CleanAndSanitizeClass which doesn't run when the skeleton class is created
|
||||
GenerateFunctions();
|
||||
}
|
||||
|
||||
void FCSCompilerContext::AddInterfacesFromBlueprint(UClass* Class)
|
||||
{
|
||||
UCSGeneratedClassBuilder::ImplementInterfaces(Class, GetTypeMetaData()->Interfaces);
|
||||
}
|
||||
|
||||
void FCSCompilerContext::TryValidateSimpleConstructionScript(const TSharedPtr<const FCSClassInfo>& ClassInfo) const
|
||||
{
|
||||
const TArray<FCSPropertyMetaData>& Properties = GetTypeMetaData()->Properties;
|
||||
FCSSimpleConstructionScriptBuilder::BuildSimpleConstructionScript(Blueprint->GeneratedClass, &Blueprint->SimpleConstructionScript, Properties);
|
||||
|
||||
if (!Blueprint->SimpleConstructionScript)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<USCS_Node*> Nodes;
|
||||
for (const FCSPropertyMetaData& Property : Properties)
|
||||
{
|
||||
if (Property.Type->PropertyType != ECSPropertyType::DefaultComponent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
USimpleConstructionScript* SCS = Blueprint->SimpleConstructionScript;
|
||||
USCS_Node* Node = SCS->FindSCSNode(Property.Name);
|
||||
Nodes.Add(Node);
|
||||
}
|
||||
|
||||
// Remove all nodes that are not part of the class anymore.
|
||||
int32 NumNodes = Blueprint->SimpleConstructionScript->GetAllNodes().Num();
|
||||
TArray<USCS_Node*> AllNodes = Blueprint->SimpleConstructionScript->GetAllNodes();
|
||||
for (int32 i = NumNodes - 1; i >= 0; --i)
|
||||
{
|
||||
USCS_Node* Node = AllNodes[i];
|
||||
if (!Nodes.Contains(Node))
|
||||
{
|
||||
Blueprint->SimpleConstructionScript->RemoveNode(Node);
|
||||
}
|
||||
}
|
||||
|
||||
Blueprint->SimpleConstructionScript->ValidateNodeTemplates(MessageLog);
|
||||
Blueprint->SimpleConstructionScript->ValidateNodeVariableNames(MessageLog);
|
||||
}
|
||||
|
||||
void FCSCompilerContext::GenerateFunctions() const
|
||||
{
|
||||
TSharedPtr<const FCSClassMetaData> TypeMetaData = GetTypeMetaData();
|
||||
|
||||
if (TypeMetaData->VirtualFunctions.IsEmpty() && TypeMetaData->Functions.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FCSFunctionFactory::GenerateVirtualFunctions(NewClass, TypeMetaData);
|
||||
FCSFunctionFactory::GenerateFunctions(NewClass, TypeMetaData->Functions);
|
||||
}
|
||||
|
||||
UCSClass* FCSCompilerContext::GetMainClass() const
|
||||
{
|
||||
return CastChecked<UCSClass>(Blueprint->GeneratedClass);
|
||||
}
|
||||
|
||||
TSharedPtr<const FCSClassInfo> FCSCompilerContext::GetClassInfo() const
|
||||
{
|
||||
return GetMainClass()->GetManagedTypeInfo<FCSClassInfo>();
|
||||
}
|
||||
|
||||
TSharedPtr<const FCSClassMetaData> FCSCompilerContext::GetTypeMetaData() const
|
||||
{
|
||||
return GetClassInfo()->GetTypeMetaData<FCSClassMetaData>();
|
||||
}
|
||||
|
||||
bool FCSCompilerContext::IsDeveloperSettings() const
|
||||
{
|
||||
return Blueprint->GeneratedClass == NewClass && NewClass->IsChildOf<UDeveloperSettings>();
|
||||
}
|
||||
|
||||
void FCSCompilerContext::TryInitializeAsDeveloperSettings(const UClass* Class) const
|
||||
{
|
||||
if (!IsDeveloperSettings())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UDeveloperSettings* Settings = static_cast<UDeveloperSettings*>(Class->GetDefaultObject());
|
||||
ISettingsModule& SettingsModule = FModuleManager::GetModuleChecked<ISettingsModule>("Settings");
|
||||
|
||||
SettingsModule.RegisterSettings(Settings->GetContainerName(), Settings->GetCategoryName(), Settings->GetSectionName(),
|
||||
Settings->GetSectionText(),
|
||||
Settings->GetSectionDescription(),
|
||||
Settings);
|
||||
|
||||
Settings->LoadConfig();
|
||||
}
|
||||
|
||||
void FCSCompilerContext::TryDeinitializeAsDeveloperSettings(UObject* Settings) const
|
||||
{
|
||||
if (!IsValid(Settings) || !IsDeveloperSettings())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ISettingsModule& SettingsModule = FModuleManager::GetModuleChecked<ISettingsModule>("Settings");
|
||||
UDeveloperSettings* DeveloperSettings = static_cast<UDeveloperSettings*>(Settings);
|
||||
SettingsModule.UnregisterSettings(DeveloperSettings->GetContainerName(), DeveloperSettings->GetCategoryName(), DeveloperSettings->GetSectionName());
|
||||
}
|
||||
|
||||
void FCSCompilerContext::ApplyMetaData()
|
||||
{
|
||||
TSharedPtr<const FCSClassMetaData> TypeMetaData = GetTypeMetaData();
|
||||
|
||||
static FString DisplayNameKey = TEXT("DisplayName");
|
||||
if (!NewClass->HasMetaData(*DisplayNameKey))
|
||||
{
|
||||
NewClass->SetMetaData(*DisplayNameKey, *Blueprint->GetName());
|
||||
}
|
||||
|
||||
if (GetDefault<UCSUnrealSharpEditorSettings>()->bSuffixGeneratedTypes)
|
||||
{
|
||||
FString DisplayName = NewClass->GetMetaData(*DisplayNameKey);
|
||||
DisplayName += TEXT(" (C#)");
|
||||
NewClass->SetMetaData(*DisplayNameKey, *DisplayName);
|
||||
}
|
||||
|
||||
FCSMetaDataUtils::ApplyMetaData(TypeMetaData->MetaData, NewClass);
|
||||
}
|
||||
|
||||
bool FCSCompilerContext::NeedsToFakeNativeClass(UClass* Class)
|
||||
{
|
||||
static TArray ParentClasses =
|
||||
{
|
||||
UBTTask_BlueprintBase::StaticClass(),
|
||||
UStateTreeTaskBlueprintBase::StaticClass(),
|
||||
};
|
||||
|
||||
for (UClass* ParentClass : ParentClasses)
|
||||
{
|
||||
if (Class->IsChildOf(ParentClass))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FCSCompilerContext::CreateDummyBlueprintVariables(const TArray<FCSPropertyMetaData>& Properties) const
|
||||
{
|
||||
Blueprint->NewVariables.Empty(Properties.Num());
|
||||
|
||||
for (const FCSPropertyMetaData& PropertyMetaData : Properties)
|
||||
{
|
||||
FBPVariableDescription VariableDescription;
|
||||
VariableDescription.FriendlyName = PropertyMetaData.Name.ToString();
|
||||
VariableDescription.VarName = PropertyMetaData.Name;
|
||||
|
||||
for (const TTuple<FString, FString>& MetaData : PropertyMetaData.MetaData)
|
||||
{
|
||||
VariableDescription.SetMetaData(*MetaData.Key, MetaData.Value);
|
||||
}
|
||||
|
||||
Blueprint->NewVariables.Add(VariableDescription);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include "KismetCompiler.h"
|
||||
|
||||
struct FCSClassMetaData;
|
||||
struct FCSPropertyMetaData;
|
||||
struct FCSClassInfo;
|
||||
class UCSClass;
|
||||
class UCSBlueprint;
|
||||
|
||||
class FCSCompilerContext : public FKismetCompilerContext
|
||||
{
|
||||
public:
|
||||
|
||||
FCSCompilerContext(UCSBlueprint* Blueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompilerOptions);
|
||||
|
||||
// FKismetCompilerContext interface
|
||||
virtual void FinishCompilingClass(UClass* Class) override;
|
||||
virtual void OnPostCDOCompiled(const UObject::FPostCDOCompiledContext& Context) override;
|
||||
virtual void CreateClassVariablesFromBlueprint() override;
|
||||
virtual void CleanAndSanitizeClass(UBlueprintGeneratedClass* ClassToClean, UObject*& OldCDO) override;
|
||||
virtual void SpawnNewClass(const FString& NewClassName) override;
|
||||
virtual void AddInterfacesFromBlueprint(UClass* Class) override;
|
||||
// End of FKismetCompilerContext interface
|
||||
protected:
|
||||
typedef FKismetCompilerContext Super;
|
||||
private:
|
||||
void TryValidateSimpleConstructionScript(const TSharedPtr<const FCSClassInfo>& ClassInfo) const;
|
||||
void GenerateFunctions() const;
|
||||
UCSClass* GetMainClass() const;
|
||||
|
||||
TSharedPtr<const FCSClassInfo> GetClassInfo() const;
|
||||
TSharedPtr<const FCSClassMetaData> GetTypeMetaData() const;
|
||||
|
||||
bool IsDeveloperSettings() const;
|
||||
void TryInitializeAsDeveloperSettings(const UClass* Class) const;
|
||||
void TryDeinitializeAsDeveloperSettings(UObject* Settings) const;
|
||||
void ApplyMetaData();
|
||||
|
||||
static bool NeedsToFakeNativeClass(UClass* Class);
|
||||
|
||||
void CreateDummyBlueprintVariables(const TArray<FCSPropertyMetaData>& Properties) const;
|
||||
};
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class UnrealSharpCompiler : ModuleRules
|
||||
{
|
||||
public UnrealSharpCompiler(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
"UnrealSharpCore",
|
||||
"KismetCompiler",
|
||||
"Kismet",
|
||||
"BlueprintGraph",
|
||||
"UnrealEd",
|
||||
"DeveloperSettings",
|
||||
"UnrealSharpEditor",
|
||||
"AIModule",
|
||||
"StateTreeModule",
|
||||
"UnrealSharpUtilities"
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,176 @@
|
||||
#include "UnrealSharpCompiler.h"
|
||||
|
||||
#include "BlueprintActionDatabase.h"
|
||||
#include "BlueprintCompilationManager.h"
|
||||
#include "CSBlueprintCompiler.h"
|
||||
#include "CSCompilerContext.h"
|
||||
#include "CSManager.h"
|
||||
#include "KismetCompiler.h"
|
||||
#include "TypeGenerator/CSBlueprint.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "TypeGenerator/CSEnum.h"
|
||||
#include "TypeGenerator/CSInterface.h"
|
||||
#include "TypeGenerator/CSScriptStruct.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FUnrealSharpCompilerModule"
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogUnrealSharpCompiler);
|
||||
|
||||
void FUnrealSharpCompilerModule::StartupModule()
|
||||
{
|
||||
UCSManager& CSManager = UCSManager::GetOrCreate();
|
||||
|
||||
FKismetCompilerContext::RegisterCompilerForBP(UCSBlueprint::StaticClass(), [](UBlueprint* InBlueprint, FCompilerResultsLog& InMessageLog, const FKismetCompilerOptions& InCompileOptions)
|
||||
{
|
||||
return MakeShared<FCSCompilerContext>(CastChecked<UCSBlueprint>(InBlueprint), InMessageLog, InCompileOptions);
|
||||
});
|
||||
|
||||
IKismetCompilerInterface& KismetCompilerModule = FModuleManager::LoadModuleChecked<IKismetCompilerInterface>("KismetCompiler");
|
||||
KismetCompilerModule.GetCompilers().Add(&BlueprintCompiler);
|
||||
|
||||
CSManager.OnNewClassEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewClass);
|
||||
CSManager.OnNewEnumEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewEnum);
|
||||
CSManager.OnNewStructEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewStruct);
|
||||
CSManager.OnNewInterfaceEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnNewInterface);
|
||||
|
||||
CSManager.OnProcessedPendingClassesEvent().AddRaw(this, &FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints);
|
||||
CSManager.OnManagedAssemblyLoadedEvent().AddRaw(this, &FUnrealSharpCompilerModule::OnManagedAssemblyLoaded);
|
||||
|
||||
// Try to recompile and reinstance all blueprints when the module is loaded.
|
||||
CSManager.ForEachManagedPackage([this](const UPackage* Package)
|
||||
{
|
||||
ForEachObjectWithPackage(Package, [this](UObject* Object)
|
||||
{
|
||||
if (UBlueprint* Blueprint = Cast<UBlueprint>(Object))
|
||||
{
|
||||
OnNewClass(static_cast<UCSClass*>(Blueprint->GeneratedClass.Get()));
|
||||
}
|
||||
return true;
|
||||
}, false);
|
||||
});
|
||||
|
||||
RecompileAndReinstanceBlueprints();
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::ShutdownModule()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::RecompileAndReinstanceBlueprints()
|
||||
{
|
||||
if (UCSManager::Get().IsLoadingAnyAssembly())
|
||||
{
|
||||
// Wait until all assemblies are loaded, so we can recompile all blueprints at once.
|
||||
return;
|
||||
}
|
||||
|
||||
if (ManagedComponentsToCompile.IsEmpty() && ManagedClassesToCompile.IsEmpty())
|
||||
{
|
||||
// Nothing to compile.
|
||||
return;
|
||||
}
|
||||
|
||||
auto CompileBlueprints = [this](TArray<UBlueprint*>& Blueprints)
|
||||
{
|
||||
if (Blueprints.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < Blueprints.Num(); ++i)
|
||||
{
|
||||
UBlueprint* Blueprint = Blueprints[i];
|
||||
|
||||
if (!Blueprint)
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint is null, skipping compilation.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsValid(Blueprint))
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharpCompiler, Error, "Blueprint {0} is garbage, skipping compilation.", *Blueprint->GetName());
|
||||
continue;
|
||||
}
|
||||
|
||||
FKismetEditorUtilities::CompileBlueprint(Blueprint, EBlueprintCompileOptions::SkipGarbageCollection);
|
||||
}
|
||||
|
||||
Blueprints.Reset();
|
||||
};
|
||||
|
||||
// Components needs be compiled first, as they are instantiated by the owning actor, and needs their size to be known.
|
||||
CompileBlueprints(ManagedComponentsToCompile);
|
||||
CompileBlueprints(ManagedClassesToCompile);
|
||||
|
||||
CollectGarbage(GARBAGE_COLLECTION_KEEPFLAGS, true);
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::AddManagedReferences(FCSManagedReferencesCollection& Collection)
|
||||
{
|
||||
Collection.ForEachManagedReference([&](UStruct* Struct)
|
||||
{
|
||||
if (UCSClass* Class = Cast<UCSClass>(Struct))
|
||||
{
|
||||
OnNewClass(Class);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::OnNewClass(UCSClass* NewClass)
|
||||
{
|
||||
UBlueprint* Blueprint = Cast<UBlueprint>(NewClass->ClassGeneratedBy);
|
||||
if (!IsValid(Blueprint))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto AddToCompileList = [this](TArray<UBlueprint*>& List, UBlueprint* Blueprint)
|
||||
{
|
||||
if (List.Contains(Blueprint))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List.Add(Blueprint);
|
||||
};
|
||||
|
||||
if (NewClass->IsChildOf(UActorComponent::StaticClass()))
|
||||
{
|
||||
AddToCompileList(ManagedComponentsToCompile, Blueprint);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddToCompileList(ManagedClassesToCompile, Blueprint);
|
||||
}
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::OnNewStruct(UCSScriptStruct* NewStruct)
|
||||
{
|
||||
AddManagedReferences(NewStruct->ManagedReferences);
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::OnNewEnum(UCSEnum* NewEnum)
|
||||
{
|
||||
AddManagedReferences(NewEnum->ManagedReferences);
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::OnNewInterface(UCSInterface* NewInterface)
|
||||
{
|
||||
if (!IsValid(GEditor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FBlueprintActionDatabase::Get().RefreshClassActions(NewInterface);
|
||||
}
|
||||
|
||||
void FUnrealSharpCompilerModule::OnManagedAssemblyLoaded(const FName& AssemblyName)
|
||||
{
|
||||
RecompileAndReinstanceBlueprints();
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FUnrealSharpCompilerModule, UnrealSharpCompiler)
|
||||
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBlueprintCompiler.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
class UCSInterface;
|
||||
struct FCSManagedReferencesCollection;
|
||||
class UCSEnum;
|
||||
class UCSScriptStruct;
|
||||
class FCSBlueprintCompiler;
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogUnrealSharpCompiler, Log, All);
|
||||
|
||||
class FUnrealSharpCompilerModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
private:
|
||||
|
||||
void OnNewClass(UCSClass* NewClass);
|
||||
void OnNewStruct(UCSScriptStruct* NewStruct);
|
||||
void OnNewEnum(UCSEnum* NewEnum);
|
||||
void OnNewInterface(UCSInterface* NewInterface);
|
||||
|
||||
void OnManagedAssemblyLoaded(const FName& AssemblyName);
|
||||
void RecompileAndReinstanceBlueprints();
|
||||
|
||||
void AddManagedReferences(FCSManagedReferencesCollection& Collection);
|
||||
|
||||
FCSBlueprintCompiler BlueprintCompiler;
|
||||
|
||||
TArray<UBlueprint*> ManagedClassesToCompile;
|
||||
TArray<UBlueprint*> ManagedComponentsToCompile;
|
||||
};
|
||||
381
Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.cpp
Normal file
381
Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.cpp
Normal file
@ -0,0 +1,381 @@
|
||||
#include "CSAssembly.h"
|
||||
#include "UnrealSharpCore.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "CSManager.h"
|
||||
#include "CSUnrealSharpSettings.h"
|
||||
#include "Logging/StructuredLog.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "TypeGenerator/CSEnum.h"
|
||||
#include "TypeGenerator/CSInterface.h"
|
||||
#include "TypeGenerator/CSScriptStruct.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSClassMetaData.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSDelegateMetaData.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSEnumMetaData.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSInterfaceMetaData.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSStructMetaData.h"
|
||||
#include "TypeGenerator/Register/TypeInfo/CSClassInfo.h"
|
||||
#include "Utils/CSClassUtilities.h"
|
||||
|
||||
void UCSAssembly::SetAssemblyPath(const FStringView InAssemblyPath)
|
||||
{
|
||||
if (!AssemblyPath.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AssemblyPath = FPaths::ConvertRelativePathToFull(InAssemblyPath.GetData());
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Replace forward slashes with backslashes
|
||||
AssemblyPath.ReplaceInline(TEXT("/"), TEXT("\\"));
|
||||
#endif
|
||||
|
||||
AssemblyName = *FPaths::GetBaseFilename(AssemblyPath);
|
||||
}
|
||||
|
||||
bool UCSAssembly::LoadAssembly(bool bisCollectible)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString(TEXT("UCSAssembly::LoadAssembly: " + AssemblyName.ToString())));
|
||||
|
||||
if (IsValidAssembly())
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Display, TEXT("%s is already loaded"), *AssemblyPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!FPaths::FileExists(AssemblyPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Display, TEXT("%s doesn't exist"), *AssemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
bIsLoading = true;
|
||||
FGCHandle NewHandle = UCSManager::Get().GetManagedPluginsCallbacks().LoadPlugin(*AssemblyPath, bisCollectible);
|
||||
NewHandle.Type = GCHandleType::WeakHandle;
|
||||
|
||||
if (NewHandle.IsNull())
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load: %s"), *AssemblyPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
ManagedAssemblyHandle = MakeShared<FGCHandle>(NewHandle);
|
||||
FModuleManager::Get().OnModulesChanged().AddUObject(this, &UCSAssembly::OnModulesChanged);
|
||||
|
||||
if (ProcessTypeMetadata())
|
||||
{
|
||||
for (const TPair<FCSFieldName, TSharedPtr<FCSManagedTypeInfo>>& NameToTypeInfo : AllTypes)
|
||||
{
|
||||
NameToTypeInfo.Value->StartBuildingManagedType();
|
||||
}
|
||||
}
|
||||
|
||||
bIsLoading = false;
|
||||
UCSManager::Get().OnManagedAssemblyLoadedEvent().Broadcast(AssemblyName);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename MetaDataType>
|
||||
void RegisterMetaData(UCSAssembly* OwningAssembly, const TSharedPtr<FJsonValue>& MetaData,
|
||||
TMap<FCSFieldName,
|
||||
TSharedPtr<FCSManagedTypeInfo>>& Map,
|
||||
UClass* FieldType,
|
||||
TFunction<void(TSharedPtr<FCSManagedTypeInfo>)> OnRebuild = nullptr)
|
||||
{
|
||||
const TSharedPtr<FJsonObject>& MetaDataObject = MetaData->AsObject();
|
||||
|
||||
const FString Name= MetaDataObject->GetStringField(TEXT("Name"));
|
||||
const FString Namespace = MetaDataObject->GetStringField(TEXT("Namespace"));
|
||||
const FCSFieldName FullName(*Name, *Namespace);
|
||||
|
||||
TSharedPtr<FCSManagedTypeInfo> ExistingValue = Map.FindRef(FullName);
|
||||
|
||||
if (ExistingValue.IsValid())
|
||||
{
|
||||
// Parse fresh metadata and update the existing info
|
||||
MetaDataType NewMeta;
|
||||
NewMeta.SerializeFromJson(MetaDataObject);
|
||||
|
||||
if (ExistingValue->GetStructureState() == HasChangedStructure || NewMeta != *ExistingValue->GetTypeMetaData<MetaDataType>())
|
||||
{
|
||||
TSharedPtr<MetaDataType> MetaDataPtr = MakeShared<MetaDataType>(NewMeta);
|
||||
ExistingValue->SetTypeMetaData(MetaDataPtr);
|
||||
ExistingValue->SetStructureState(HasChangedStructure);
|
||||
|
||||
if (OnRebuild)
|
||||
{
|
||||
OnRebuild(ExistingValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TSharedPtr<MetaDataType> ParsedMeta = MakeShared<MetaDataType>();
|
||||
ParsedMeta->SerializeFromJson(MetaDataObject);
|
||||
|
||||
TSharedPtr<T> NewValue = MakeShared<T>(ParsedMeta, OwningAssembly, FieldType);
|
||||
Map.Add(FullName, NewValue);
|
||||
}
|
||||
}
|
||||
|
||||
bool UCSAssembly::ProcessTypeMetadata()
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::ProcessTypeMetadata);
|
||||
|
||||
const FString MetadataPath = FPaths::ChangeExtension(AssemblyPath, "metadata.json");
|
||||
if (!FPaths::FileExists(MetadataPath))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
FString JsonString;
|
||||
if (!FFileHelper::LoadFileToString(JsonString, *MetadataPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load MetaDataPath at: %s"), *MetadataPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
TSharedPtr<FJsonObject> JsonObject;
|
||||
if (!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), JsonObject) || !JsonObject.IsValid())
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to parse JSON at: %s"), *MetadataPath);
|
||||
return false;
|
||||
}
|
||||
|
||||
UCSManager& Manager = UCSManager::Get();
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>& StructMetaData = JsonObject->GetArrayField(TEXT("StructMetaData"));
|
||||
for (const TSharedPtr<FJsonValue>& MetaData : StructMetaData)
|
||||
{
|
||||
RegisterMetaData<FCSManagedTypeInfo, FCSStructMetaData>(this, MetaData, AllTypes, UCSScriptStruct::StaticClass());
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>& EnumMetaData = JsonObject->GetArrayField(TEXT("EnumMetaData"));
|
||||
for (const TSharedPtr<FJsonValue>& MetaData : EnumMetaData)
|
||||
{
|
||||
RegisterMetaData<FCSManagedTypeInfo, FCSEnumMetaData>(this, MetaData, AllTypes, UCSEnum::StaticClass());
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>& InterfacesMetaData = JsonObject->GetArrayField(TEXT("InterfacesMetaData"));
|
||||
for (const TSharedPtr<FJsonValue>& MetaData : InterfacesMetaData)
|
||||
{
|
||||
RegisterMetaData<FCSManagedTypeInfo, FCSInterfaceMetaData>(this, MetaData, AllTypes, UCSInterface::StaticClass());
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>& DelegatesMetaData = JsonObject->GetArrayField(TEXT("DelegateMetaData"));
|
||||
for (const TSharedPtr<FJsonValue>& MetaData : DelegatesMetaData)
|
||||
{
|
||||
RegisterMetaData<FCSManagedTypeInfo, FCSDelegateMetaData>(this, MetaData, AllTypes, UDelegateFunction::StaticClass());
|
||||
}
|
||||
|
||||
const TArray<TSharedPtr<FJsonValue>>& ClassesMetaData = JsonObject->GetArrayField(TEXT("ClassMetaData"));
|
||||
for (const TSharedPtr<FJsonValue>& MetaData : ClassesMetaData)
|
||||
{
|
||||
RegisterMetaData<FCSClassInfo, FCSClassMetaData>(this, MetaData, AllTypes, UCSClass::StaticClass(),
|
||||
[&Manager](const TSharedPtr<FCSManagedTypeInfo>& ClassInfo)
|
||||
{
|
||||
// Structure has been changed. We must trigger full reload on all managed classes that derive from this class.
|
||||
TArray<UClass*> DerivedClasses;
|
||||
GetDerivedClasses(ClassInfo->GetFieldChecked<UClass>(), DerivedClasses);
|
||||
|
||||
for (UClass* DerivedClass : DerivedClasses)
|
||||
{
|
||||
if (!Manager.IsManagedType(DerivedClass))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UCSClass* ManagedClass = static_cast<UCSClass*>(DerivedClass);
|
||||
TSharedPtr<FCSClassInfo> ChildClassInfo = ManagedClass->GetManagedTypeInfo<FCSClassInfo>();
|
||||
ChildClassInfo->SetStructureState(HasChangedStructure);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UCSAssembly::UnloadAssembly()
|
||||
{
|
||||
if (!IsValidAssembly())
|
||||
{
|
||||
// Assembly is already unloaded.
|
||||
UE_LOGFMT(LogUnrealSharp, Display, "{0} is already unloaded", *AssemblyName.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE_TEXT(*FString(TEXT("UCSAssembly::UnloadAssembly: " + AssemblyName.ToString())));
|
||||
|
||||
FGCHandleIntPtr AssemblyHandle = ManagedAssemblyHandle->GetHandle();
|
||||
for (TSharedPtr<FGCHandle>& Handle : AllocatedManagedHandles)
|
||||
{
|
||||
Handle->Dispose(AssemblyHandle);
|
||||
Handle.Reset();
|
||||
}
|
||||
|
||||
ManagedClassHandles.Reset();
|
||||
AllocatedManagedHandles.Reset();
|
||||
|
||||
// Don't need the assembly handle anymore, we use the path to unload the assembly.
|
||||
ManagedAssemblyHandle->Dispose(ManagedAssemblyHandle->GetHandle());
|
||||
ManagedAssemblyHandle.Reset();
|
||||
|
||||
UCSManager::Get().OnManagedAssemblyUnloadedEvent().Broadcast(AssemblyName);
|
||||
return UCSManager::Get().GetManagedPluginsCallbacks().UnloadPlugin(*AssemblyPath);
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> UCSAssembly::TryFindTypeHandle(const FCSFieldName& FieldName)
|
||||
{
|
||||
if (!IsValidAssembly())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (TSharedPtr<FGCHandle>* Handle = ManagedClassHandles.Find(FieldName))
|
||||
{
|
||||
return *Handle;
|
||||
}
|
||||
|
||||
FString FullName = FieldName.GetFullName().ToString();
|
||||
uint8* TypeHandle = FCSManagedCallbacks::ManagedCallbacks.LookupManagedType(ManagedAssemblyHandle->GetPointer(), *FullName);
|
||||
|
||||
if (!TypeHandle)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> AllocatedHandle = MakeShared<FGCHandle>(TypeHandle, GCHandleType::WeakHandle);
|
||||
AllocatedManagedHandles.Add(AllocatedHandle);
|
||||
ManagedClassHandles.Add(FieldName, AllocatedHandle);
|
||||
return AllocatedHandle;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> UCSAssembly::GetManagedMethod(const TSharedPtr<FGCHandle>& TypeHandle, const FString& MethodName)
|
||||
{
|
||||
if (!TypeHandle.IsValid())
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Error, "Type handle is invalid for method %s", *MethodName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8* MethodHandle = FCSManagedCallbacks::ManagedCallbacks.LookupManagedMethod(TypeHandle->GetPointer(), *MethodName);
|
||||
|
||||
if (MethodHandle == nullptr)
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Failed to find managed method for %s"), *MethodName);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> AllocatedHandle = MakeShared<FGCHandle>(MethodHandle, GCHandleType::WeakHandle);
|
||||
AllocatedManagedHandles.Add(AllocatedHandle);
|
||||
return AllocatedHandle;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> UCSAssembly::CreateManagedObject(const UObject* Object)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::CreateManagedObject);
|
||||
|
||||
// Only managed/native classes have a C# counterpart.
|
||||
UClass* Class = FCSClassUtilities::GetFirstNonBlueprintClass(Object->GetClass());
|
||||
TSharedPtr<FCSManagedTypeInfo> TypeInfo = FindOrAddTypeInfo(Class);
|
||||
TSharedPtr<FGCHandle> TypeHandle = TypeInfo->GetManagedTypeHandle();
|
||||
|
||||
TCHAR* Error = nullptr;
|
||||
FGCHandle NewManagedObject = FCSManagedCallbacks::ManagedCallbacks.CreateNewManagedObject(Object, TypeHandle->GetPointer(), &Error);
|
||||
NewManagedObject.Type = GCHandleType::StrongHandle;
|
||||
|
||||
if (NewManagedObject.IsNull())
|
||||
{
|
||||
// This should never happen. Potential issues: IL errors, typehandle is invalid.
|
||||
UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to create managed counterpart for {0}:\n{1}", *Object->GetName(), Error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> Handle = MakeShared<FGCHandle>(NewManagedObject);
|
||||
AllocatedManagedHandles.Add(Handle);
|
||||
|
||||
uint32 ObjectID = Object->GetUniqueID();
|
||||
UCSManager::Get().ManagedObjectHandles.AddByHash(ObjectID, ObjectID, Handle);
|
||||
|
||||
return Handle;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> UCSAssembly::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindOrCreateManagedInterfaceWrapper);
|
||||
|
||||
UClass* NonBlueprintClass = FCSClassUtilities::GetFirstNonBlueprintClass(InterfaceClass);
|
||||
TSharedPtr<FCSManagedTypeInfo> ClassInfo = FindOrAddTypeInfo(NonBlueprintClass);
|
||||
TSharedPtr<FGCHandle> TypeHandle = ClassInfo->GetManagedTypeHandle();
|
||||
|
||||
uint32 ObjectID = Object->GetUniqueID();
|
||||
TMap<uint32, TSharedPtr<FGCHandle>>& TypeMap = UCSManager::Get().ManagedInterfaceWrappers.FindOrAddByHash(ObjectID, ObjectID);
|
||||
|
||||
uint32 TypeId = InterfaceClass->GetUniqueID();
|
||||
if (TSharedPtr<FGCHandle>* Existing = TypeMap.FindByHash(TypeId, TypeId))
|
||||
{
|
||||
return *Existing;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle>* ObjectHandle = UCSManager::Get().ManagedObjectHandles.FindByHash(ObjectID, ObjectID);
|
||||
if (ObjectHandle == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FGCHandle NewManagedObjectWrapper = FCSManagedCallbacks::ManagedCallbacks.CreateNewManagedObjectWrapper((*ObjectHandle)->GetPointer(), TypeHandle->GetPointer());
|
||||
NewManagedObjectWrapper.Type = GCHandleType::StrongHandle;
|
||||
|
||||
if (NewManagedObjectWrapper.IsNull())
|
||||
{
|
||||
// This should never happen. Potential issues: IL errors, typehandle is invalid.
|
||||
UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to create managed counterpart for {0}", *Object->GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> Handle = MakeShared<FGCHandle>(NewManagedObjectWrapper);
|
||||
AllocatedManagedHandles.Add(Handle);
|
||||
|
||||
TypeMap.AddByHash(TypeId, TypeId, Handle);
|
||||
return Handle;
|
||||
}
|
||||
|
||||
void UCSAssembly::AddPendingClass(const FCSTypeReferenceMetaData& ParentClass, FCSClassInfo* NewClass)
|
||||
{
|
||||
TSet<FCSClassInfo*>& PendingClass = PendingClasses.FindOrAdd(ParentClass);
|
||||
PendingClass.Add(NewClass);
|
||||
}
|
||||
|
||||
void UCSAssembly::OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason)
|
||||
{
|
||||
if (InModuleChangeReason != EModuleChangeReason::ModuleLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32 NumPendingClasses = PendingClasses.Num();
|
||||
for (auto Itr = PendingClasses.CreateIterator(); Itr; ++Itr)
|
||||
{
|
||||
UClass* Class = Itr.Key().GetOwningClass();
|
||||
|
||||
if (!Class)
|
||||
{
|
||||
// Class still not loaded from this module.
|
||||
continue;
|
||||
}
|
||||
|
||||
for (FCSClassInfo* PendingClass : Itr.Value())
|
||||
{
|
||||
PendingClass->StartBuildingManagedType();
|
||||
}
|
||||
|
||||
Itr.RemoveCurrent();
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
if (NumPendingClasses != PendingClasses.Num())
|
||||
{
|
||||
UCSManager::Get().OnProcessedPendingClassesEvent().Broadcast();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
173
Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.h
Normal file
173
Plugins/UnrealSharp/Source/UnrealSharpCore/CSAssembly.h
Normal file
@ -0,0 +1,173 @@
|
||||
#pragma once
|
||||
|
||||
#include "CSManagedGCHandle.h"
|
||||
#include "UnrealSharpCore.h"
|
||||
#include "Logging/StructuredLog.h"
|
||||
#include "TypeGenerator/Register/MetaData/CSTypeReferenceMetaData.h"
|
||||
#include "Utils/CSClassUtilities.h"
|
||||
#include "CSAssembly.generated.h"
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
struct FCSClassInfo;
|
||||
struct FCSManagedMethod;
|
||||
class UCSClass;
|
||||
|
||||
/**
|
||||
* Represents a managed assembly.
|
||||
* This class is responsible for loading and unloading the assembly, as well as managing all types that are defined in the C# assembly.
|
||||
*/
|
||||
UCLASS()
|
||||
class UCSAssembly : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
void SetAssemblyPath(const FStringView InAssemblyPath);
|
||||
|
||||
UNREALSHARPCORE_API bool LoadAssembly(bool bIsCollectible = true);
|
||||
UNREALSHARPCORE_API bool UnloadAssembly();
|
||||
UNREALSHARPCORE_API bool IsValidAssembly() const { return ManagedAssemblyHandle.IsValid() && !ManagedAssemblyHandle->IsNull(); }
|
||||
|
||||
FName GetAssemblyName() const { return AssemblyName; }
|
||||
const FString& GetAssemblyPath() const { return AssemblyPath; }
|
||||
|
||||
bool IsLoading() const { return bIsLoading; }
|
||||
|
||||
TSharedPtr<FGCHandle> TryFindTypeHandle(const FCSFieldName& FieldName);
|
||||
TSharedPtr<FGCHandle> GetManagedMethod(const TSharedPtr<FGCHandle>& TypeHandle, const FString& MethodName);
|
||||
|
||||
template<typename T = FCSManagedTypeInfo>
|
||||
TSharedPtr<T> FindOrAddTypeInfo(UClass* Field)
|
||||
{
|
||||
if (ICSManagedTypeInterface* ManagedClass = FCSClassUtilities::GetManagedType(Field))
|
||||
{
|
||||
return ManagedClass->GetManagedTypeInfo<T>();
|
||||
}
|
||||
|
||||
FCSFieldName FieldName(Field);
|
||||
return FindOrAddTypeInfo<T>(FieldName);
|
||||
}
|
||||
|
||||
template<typename T = FCSManagedTypeInfo>
|
||||
TSharedPtr<T> FindOrAddTypeInfo(const FCSFieldName& ClassName)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindOrAddClassInfo);
|
||||
|
||||
TSharedPtr<FCSManagedTypeInfo>& TypeInfo = AllTypes.FindOrAdd(ClassName);
|
||||
|
||||
// Native types are populated on the go when they are needed for managed code execution.
|
||||
if (!TypeInfo.IsValid())
|
||||
{
|
||||
UField* Field = TryFindField(ClassName);
|
||||
|
||||
if (!IsValid(Field))
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Error, "Failed to find native class: {0}", *ClassName.GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeInfo = MakeShared<FCSManagedTypeInfo>(Field, this);
|
||||
}
|
||||
|
||||
if constexpr (std::is_same_v<T, FCSManagedTypeInfo>)
|
||||
{
|
||||
return TypeInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
return StaticCastSharedPtr<T>(TypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T = FCSManagedTypeInfo>
|
||||
TSharedPtr<T> FindTypeInfo(const FCSFieldName& FieldName) const
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindClassInfo);
|
||||
static_assert(TIsDerivedFrom<T, FCSManagedTypeInfo>::Value, "T must be a FCSManagedTypeInfo-derived type.");
|
||||
|
||||
const TSharedPtr<FCSManagedTypeInfo>* TypeInfo = AllTypes.Find(FieldName);
|
||||
if (TypeInfo && TypeInfo->IsValid())
|
||||
{
|
||||
return StaticCastSharedPtr<T>(*TypeInfo);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename T = UField>
|
||||
T* FindType(const FCSFieldName& FieldName) const
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSAssembly::FindType);
|
||||
static_assert(TIsDerivedFrom<T, UField>::Value, "T must be a UField-derived type.");
|
||||
|
||||
TSharedPtr<FCSManagedTypeInfo> TypeInfo = AllTypes.FindRef(FieldName);
|
||||
if (TypeInfo.IsValid())
|
||||
{
|
||||
return Cast<T>(TypeInfo->StartBuildingManagedType());
|
||||
}
|
||||
|
||||
return TryFindField<T>(FieldName);
|
||||
}
|
||||
|
||||
// Creates a C# counterpart for the given UObject.
|
||||
TSharedPtr<FGCHandle> CreateManagedObject(const UObject* Object);
|
||||
TSharedPtr<FGCHandle> FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass);
|
||||
|
||||
// Add a class that is waiting for its parent class to be loaded before it can be created.
|
||||
void AddPendingClass(const FCSTypeReferenceMetaData& ParentClass, FCSClassInfo* NewClass);
|
||||
|
||||
TSharedPtr<const FGCHandle> GetManagedAssemblyHandle() const { return ManagedAssemblyHandle; }
|
||||
|
||||
private:
|
||||
|
||||
bool ProcessTypeMetadata();
|
||||
|
||||
void OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason);
|
||||
|
||||
template<typename T = UField>
|
||||
T* TryFindField(const FCSFieldName FieldName) const
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::TryFindField);
|
||||
static_assert(TIsDerivedFrom<T, UObject>::Value, "T must be a UObject-derived type.");
|
||||
|
||||
if (!FieldName.IsValid())
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Warning, "Invalid field name: {0}", *FieldName.GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UPackage* Package = FieldName.GetPackage();
|
||||
if (!IsValid(Package))
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Warning, "Failed to find package for field: {0}", *FieldName.GetName());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return FindObject<T>(Package, *FieldName.GetName());
|
||||
}
|
||||
|
||||
// All Unreal types that are defined in this assembly.
|
||||
TMap<FCSFieldName, TSharedPtr<FCSManagedTypeInfo>> AllTypes;
|
||||
|
||||
// All handles allocated by this assembly. Handles to types, methods, objects.
|
||||
TArray<TSharedPtr<FGCHandle>> AllocatedManagedHandles;
|
||||
|
||||
// Handles to all allocated UTypes (UClass/UStruct, etc) that are defined in this assembly.
|
||||
TMap<FCSFieldName, TSharedPtr<FGCHandle>> ManagedClassHandles;
|
||||
|
||||
// Pending classes that are waiting for their parent class to be loaded by the engine.
|
||||
TMap<FCSTypeReferenceMetaData, TSet<FCSClassInfo*>> PendingClasses;
|
||||
|
||||
// Handle to the Assembly object in C#.
|
||||
TSharedPtr<FGCHandle> ManagedAssemblyHandle;
|
||||
|
||||
// Full path to the assembly file.
|
||||
FString AssemblyPath;
|
||||
|
||||
// Assembly file name without the path.
|
||||
FName AssemblyName;
|
||||
|
||||
bool bIsLoading = false;
|
||||
};
|
||||
14
Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.cpp
Normal file
14
Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "CSFieldName.h"
|
||||
#include "UnrealSharpUtilities/UnrealSharpUtils.h"
|
||||
#include "Utils/CSClassUtilities.h"
|
||||
|
||||
FCSFieldName::FCSFieldName(UField* Field)
|
||||
{
|
||||
if (UClass* Class = Cast<UClass>(Field))
|
||||
{
|
||||
Field = FCSClassUtilities::GetFirstNativeClass(Class);
|
||||
}
|
||||
|
||||
Name = Field->GetFName();
|
||||
Namespace = FCSUnrealSharpUtils::GetNamespace(Field);
|
||||
}
|
||||
37
Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.h
Normal file
37
Plugins/UnrealSharp/Source/UnrealSharpCore/CSFieldName.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "CSNamespace.h"
|
||||
|
||||
struct UNREALSHARPCORE_API FCSFieldName
|
||||
{
|
||||
FCSFieldName() = default;
|
||||
FCSFieldName(FName Name, FName Namespace) : Name(Name), Namespace(Namespace) {}
|
||||
FCSFieldName(UField* Field);
|
||||
|
||||
FName GetFName() const { return Name; }
|
||||
FString GetName() const { return Name.ToString(); }
|
||||
|
||||
bool IsValid() const { return Name != NAME_None; }
|
||||
|
||||
FCSNamespace GetNamespace() const { return Namespace; }
|
||||
UPackage* GetPackage() const { return Namespace.GetPackage(); }
|
||||
FName GetPackageName() const { return Namespace.GetPackageName(); }
|
||||
|
||||
FName GetFullName() const
|
||||
{
|
||||
return *FString::Printf(TEXT("%s.%s"), *Namespace.GetName(), *Name.ToString());
|
||||
}
|
||||
|
||||
bool operator == (const FCSFieldName& Other) const
|
||||
{
|
||||
return Name == Other.Name && Namespace == Other.Namespace;
|
||||
}
|
||||
|
||||
friend uint32 GetTypeHash(const FCSFieldName& Field)
|
||||
{
|
||||
return GetTypeHash(Field.Name) ^ GetTypeHash(Field.Namespace);
|
||||
}
|
||||
private:
|
||||
FName Name;
|
||||
FCSNamespace Namespace;
|
||||
};
|
||||
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
struct FScopedGCHandle;
|
||||
struct FInvokeManagedMethodData;
|
||||
struct FGCHandleIntPtr;
|
||||
struct FGCHandle;
|
||||
|
||||
class UNREALSHARPCORE_API FCSManagedCallbacks
|
||||
{
|
||||
public:
|
||||
|
||||
struct FManagedCallbacks
|
||||
{
|
||||
using ManagedCallbacks_CreateNewManagedObject = FGCHandleIntPtr(__stdcall*)(const void*, void*, TCHAR**);
|
||||
using ManagedCallbacks_CreateNewManagedObjectWrapper = FGCHandleIntPtr(__stdcall*)(void*, void*);
|
||||
using ManagedCallbacks_InvokeManagedEvent = int(__stdcall*)(void*, void*, void*, void*, void*);
|
||||
using ManagedCallbacks_InvokeDelegate = int(__stdcall*)(FGCHandleIntPtr);
|
||||
using ManagedCallbacks_LookupMethod = uint8*(__stdcall*)(void*, const TCHAR*);
|
||||
using ManagedCallbacks_LookupType = uint8*(__stdcall*)(uint8*, const TCHAR*);
|
||||
using ManagedCallbacks_Dispose = void(__stdcall*)(FGCHandleIntPtr, FGCHandleIntPtr);
|
||||
using ManagedCallbacks_FreeHandle = void(__stdcall*)(FGCHandleIntPtr);
|
||||
|
||||
ManagedCallbacks_CreateNewManagedObject CreateNewManagedObject;
|
||||
ManagedCallbacks_CreateNewManagedObjectWrapper CreateNewManagedObjectWrapper;
|
||||
ManagedCallbacks_InvokeManagedEvent InvokeManagedMethod;
|
||||
ManagedCallbacks_InvokeDelegate InvokeDelegate;
|
||||
ManagedCallbacks_LookupMethod LookupManagedMethod;
|
||||
ManagedCallbacks_LookupType LookupManagedType;
|
||||
|
||||
private:
|
||||
//Only call these from GCHandles.
|
||||
friend FGCHandle;
|
||||
friend FScopedGCHandle;
|
||||
ManagedCallbacks_Dispose Dispose;
|
||||
ManagedCallbacks_FreeHandle FreeHandle;
|
||||
};
|
||||
|
||||
static inline FManagedCallbacks ManagedCallbacks;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
#include "CSManagedDelegate.h"
|
||||
|
||||
#include "CSManager.h"
|
||||
|
||||
void FCSManagedDelegate::Invoke(UObject* WorldContextObject, bool bDispose)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(FCSManagedDelegate::Invoke);
|
||||
|
||||
if (CallbackHandle.IsNull())
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Warning, "FCSManagedDelegate::Invoke: CallbackHandle is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsValid(WorldContextObject))
|
||||
{
|
||||
UCSManager::Get().SetCurrentWorldContext(WorldContextObject);
|
||||
}
|
||||
|
||||
FCSManagedCallbacks::ManagedCallbacks.InvokeDelegate(CallbackHandle.GetHandle());
|
||||
|
||||
if (bDispose)
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "CSManagedGCHandle.h"
|
||||
|
||||
struct UNREALSHARPCORE_API FCSManagedDelegate
|
||||
{
|
||||
FCSManagedDelegate(const FGCHandle& ManagedDelegate)
|
||||
: CallbackHandle(ManagedDelegate)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FCSManagedDelegate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Invoke(UObject* WorldContextObject = nullptr, bool bDispose = true);
|
||||
void Dispose() { CallbackHandle.Dispose(); }
|
||||
|
||||
private:
|
||||
FGCHandle CallbackHandle;
|
||||
};
|
||||
124
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManagedGCHandle.h
Normal file
124
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManagedGCHandle.h
Normal file
@ -0,0 +1,124 @@
|
||||
#pragma once
|
||||
#include "CSManagedCallbacksCache.h"
|
||||
#include "CSManagedGCHandle.generated.h"
|
||||
|
||||
enum class GCHandleType : char
|
||||
{
|
||||
Null,
|
||||
StrongHandle,
|
||||
WeakHandle,
|
||||
PinnedHandle,
|
||||
};
|
||||
|
||||
struct FGCHandleIntPtr
|
||||
{
|
||||
bool operator == (const FGCHandleIntPtr& Other) const
|
||||
{
|
||||
return IntPtr == Other.IntPtr;
|
||||
}
|
||||
|
||||
bool operator != (const FGCHandleIntPtr& Other) const
|
||||
{
|
||||
return IntPtr != Other.IntPtr;
|
||||
}
|
||||
|
||||
// Pointer to the managed object in C#
|
||||
uint8* IntPtr = nullptr;
|
||||
};
|
||||
|
||||
static_assert(sizeof(FGCHandleIntPtr) == sizeof(void *));
|
||||
|
||||
struct FGCHandle
|
||||
{
|
||||
FGCHandleIntPtr Handle;
|
||||
GCHandleType Type = GCHandleType::Null;
|
||||
|
||||
static FGCHandle Null() { return FGCHandle(nullptr, GCHandleType::Null); }
|
||||
|
||||
bool IsNull() const { return !Handle.IntPtr; }
|
||||
bool IsWeakPointer() const { return Type == GCHandleType::WeakHandle; }
|
||||
|
||||
FGCHandleIntPtr GetHandle() const { return Handle; }
|
||||
uint8* GetPointer() const { return Handle.IntPtr; };
|
||||
|
||||
void Dispose(FGCHandleIntPtr AssemblyHandle = FGCHandleIntPtr())
|
||||
{
|
||||
if (!Handle.IntPtr || Type == GCHandleType::Null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FCSManagedCallbacks::ManagedCallbacks.Dispose(Handle, AssemblyHandle);
|
||||
|
||||
Handle.IntPtr = nullptr;
|
||||
Type = GCHandleType::Null;
|
||||
}
|
||||
|
||||
void operator = (const FGCHandle& Other)
|
||||
{
|
||||
Handle = Other.Handle;
|
||||
Type = Other.Type;
|
||||
}
|
||||
|
||||
operator void*() const
|
||||
{
|
||||
return Handle.IntPtr;
|
||||
}
|
||||
|
||||
FGCHandle(){}
|
||||
FGCHandle(const FGCHandleIntPtr InHandle, const GCHandleType InType) : Handle(InHandle), Type(InType) {}
|
||||
|
||||
FGCHandle(uint8* InHandle, const GCHandleType InType) : Type(InType)
|
||||
{
|
||||
Handle.IntPtr = InHandle;
|
||||
}
|
||||
|
||||
FGCHandle(const FGCHandleIntPtr InHandle) : Handle(InHandle)
|
||||
{
|
||||
Type = GCHandleType::Null;
|
||||
}
|
||||
};
|
||||
|
||||
struct FScopedGCHandle
|
||||
{
|
||||
|
||||
FGCHandleIntPtr Handle;
|
||||
|
||||
explicit FScopedGCHandle(FGCHandleIntPtr InHandle) : Handle(InHandle) {}
|
||||
|
||||
FScopedGCHandle(const FScopedGCHandle&) = delete;
|
||||
FScopedGCHandle(FScopedGCHandle&&) = delete;
|
||||
|
||||
~FScopedGCHandle()
|
||||
{
|
||||
if (Handle.IntPtr != nullptr)
|
||||
{
|
||||
FCSManagedCallbacks::ManagedCallbacks.FreeHandle(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
FScopedGCHandle& operator=(const FScopedGCHandle&) = delete;
|
||||
FScopedGCHandle& operator=(FScopedGCHandle&&) = delete;
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FSharedGCHandle
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FSharedGCHandle() = default;
|
||||
explicit FSharedGCHandle(FGCHandleIntPtr InHandle) : Handle(MakeShared<FScopedGCHandle>(InHandle)) {}
|
||||
|
||||
FGCHandleIntPtr GetHandle() const
|
||||
{
|
||||
if (Handle == nullptr)
|
||||
{
|
||||
return FGCHandleIntPtr();
|
||||
}
|
||||
|
||||
return Handle->Handle;
|
||||
}
|
||||
|
||||
private:
|
||||
TSharedPtr<FScopedGCHandle> Handle;
|
||||
};
|
||||
678
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.cpp
Normal file
678
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.cpp
Normal file
@ -0,0 +1,678 @@
|
||||
#include "CSManager.h"
|
||||
#include "CSManagedGCHandle.h"
|
||||
#include "CSAssembly.h"
|
||||
#include "UnrealSharpCore.h"
|
||||
#include "TypeGenerator/CSClass.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Misc/App.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "UnrealSharpProcHelper/CSProcHelper.h"
|
||||
#include <vector>
|
||||
#include "CSBindsManager.h"
|
||||
#include "CSNamespace.h"
|
||||
#include "CSUnrealSharpSettings.h"
|
||||
#include "Engine/UserDefinedEnum.h"
|
||||
#include "Logging/StructuredLog.h"
|
||||
#include "StructUtils/UserDefinedStruct.h"
|
||||
#include "TypeGenerator/CSInterface.h"
|
||||
#include "TypeGenerator/Factories/CSPropertyFactory.h"
|
||||
#include "TypeGenerator/Register/CSBuilderManager.h"
|
||||
#include "TypeGenerator/Register/TypeInfo/CSClassInfo.h"
|
||||
#include "Utils/CSClassUtilities.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PLATFORM_STRING(string) string
|
||||
#elif defined(__unix__)
|
||||
#define PLATFORM_STRING(string) TCHAR_TO_ANSI(string)
|
||||
#elif defined(__APPLE__)
|
||||
#define PLATFORM_STRING(string) TCHAR_TO_ANSI(string)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wdangling-assignment"
|
||||
#endif
|
||||
|
||||
UCSManager* UCSManager::Instance = nullptr;
|
||||
|
||||
UPackage* UCSManager::FindOrAddManagedPackage(const FCSNamespace Namespace)
|
||||
{
|
||||
if (UPackage* NativePackage = Namespace.TryGetAsNativePackage())
|
||||
{
|
||||
return NativePackage;
|
||||
}
|
||||
|
||||
FCSNamespace CurrentNamespace = Namespace;
|
||||
TArray<FCSNamespace> ParentNamespaces;
|
||||
while (true)
|
||||
{
|
||||
ParentNamespaces.Add(CurrentNamespace);
|
||||
|
||||
if (!CurrentNamespace.GetParentNamespace(CurrentNamespace))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UPackage* ParentPackage = nullptr;
|
||||
for (int32 i = ParentNamespaces.Num() - 1; i >= 0; i--)
|
||||
{
|
||||
FCSNamespace ParentNamespace = ParentNamespaces[i];
|
||||
FName PackageName = ParentNamespace.GetPackageName();
|
||||
|
||||
for (UPackage* Package : AllPackages)
|
||||
{
|
||||
if (PackageName == Package->GetFName())
|
||||
{
|
||||
ParentPackage = Package;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParentPackage)
|
||||
{
|
||||
ParentPackage = NewObject<UPackage>(nullptr, PackageName, RF_Public);
|
||||
ParentPackage->SetPackageFlags(PKG_CompiledIn);
|
||||
AllPackages.Add(ParentPackage);
|
||||
}
|
||||
}
|
||||
|
||||
return ParentPackage;
|
||||
}
|
||||
|
||||
void UCSManager::ForEachManagedField(const TFunction<void(UObject*)>& Callback) const
|
||||
{
|
||||
for (UPackage* Package : AllPackages)
|
||||
{
|
||||
ForEachObjectWithPackage(Package, [&Callback](UObject* Object)
|
||||
{
|
||||
Callback(Object);
|
||||
return true;
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
UPackage* UCSManager::GetPackage(const FCSNamespace Namespace)
|
||||
{
|
||||
UPackage* FoundPackage;
|
||||
if (GetDefault<UCSUnrealSharpSettings>()->HasNamespaceSupport())
|
||||
{
|
||||
FoundPackage = FindOrAddManagedPackage(Namespace);
|
||||
}
|
||||
else
|
||||
{
|
||||
FoundPackage = GetGlobalManagedPackage();
|
||||
}
|
||||
|
||||
return FoundPackage;
|
||||
}
|
||||
|
||||
bool UCSManager::IsLoadingAnyAssembly() const
|
||||
{
|
||||
for (const TPair<FName, TObjectPtr<UCSAssembly>>& LoadedAssembly : LoadedAssemblies)
|
||||
{
|
||||
UCSAssembly* AssemblyPtr = LoadedAssembly.Value;
|
||||
if (IsValid(AssemblyPtr) && AssemblyPtr->IsLoading())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UCSManager::AddDynamicSubsystemClass(TSubclassOf<UDynamicSubsystem> SubsystemClass)
|
||||
{
|
||||
if (!IsValid(SubsystemClass))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Warning, TEXT("Tried to add an invalid dynamic subsystem class"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!PendingDynamicSubsystemClasses.Contains(SubsystemClass))
|
||||
{
|
||||
PendingDynamicSubsystemClasses.Add(SubsystemClass);
|
||||
}
|
||||
|
||||
TryInitializeDynamicSubsystems();
|
||||
}
|
||||
|
||||
void UCSManager::Initialize()
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FString DotNetInstallationPath = FCSProcHelper::GetDotNetDirectory();
|
||||
if (DotNetInstallationPath.IsEmpty())
|
||||
{
|
||||
FString DialogText = FString::Printf(TEXT("UnrealSharp can't be initialized. An installation of .NET %s SDK can't be found on your system."), TEXT(DOTNET_MAJOR_VERSION));
|
||||
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(DialogText));
|
||||
return;
|
||||
}
|
||||
|
||||
FString UnrealSharpLibraryPath = FCSProcHelper::GetUnrealSharpPluginsPath();
|
||||
if (!FPaths::FileExists(UnrealSharpLibraryPath))
|
||||
{
|
||||
FString FullPath = FPaths::ConvertRelativePathToFull(UnrealSharpLibraryPath);
|
||||
FString DialogText = FString::Printf(TEXT(
|
||||
"The bindings library could not be found at the following location:\n%s\n\n"
|
||||
"Most likely, the bindings library failed to build due to invalid generated glue."
|
||||
), *FullPath);
|
||||
|
||||
FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(DialogText));
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<FString> ProjectPaths;
|
||||
FCSProcHelper::GetAllProjectPaths(ProjectPaths);
|
||||
|
||||
// Compile the C# project for any changes done outside the editor.
|
||||
if (!ProjectPaths.IsEmpty() && !FApp::IsUnattended() && !FCSProcHelper::InvokeUnrealSharpBuildTool(BUILD_ACTION_BUILD_WEAVE))
|
||||
{
|
||||
Initialize();
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove this listener when the engine is shutting down.
|
||||
// Otherwise, we'll get a crash when the GC cleans up all the UObject.
|
||||
FCoreDelegates::OnPreExit.AddUObject(this, &UCSManager::OnEnginePreExit);
|
||||
#endif
|
||||
|
||||
TypeBuilderManager = NewObject<UCSTypeBuilderManager>(this);
|
||||
TypeBuilderManager->Initialize();
|
||||
|
||||
GUObjectArray.AddUObjectDeleteListener(this);
|
||||
|
||||
// Initialize the C# runtime.
|
||||
if (!InitializeDotNetRuntime())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GlobalManagedPackage = FindOrAddManagedPackage(FCSNamespace(TEXT("UnrealSharp")));
|
||||
|
||||
// Initialize the property factory. This is used to create properties for managed structs/classes/functions.
|
||||
FCSPropertyFactory::Initialize();
|
||||
|
||||
// Try to load the user assembly. Can be empty if the user hasn't created any csproj yet.
|
||||
LoadAllUserAssemblies();
|
||||
|
||||
FModuleManager::Get().OnModulesChanged().AddUObject(this, &UCSManager::OnModulesChanged);
|
||||
}
|
||||
|
||||
bool UCSManager::InitializeDotNetRuntime()
|
||||
{
|
||||
if (!LoadRuntimeHost())
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to load Runtime Host"));
|
||||
return false;
|
||||
}
|
||||
|
||||
load_assembly_and_get_function_pointer_fn LoadAssemblyAndGetFunctionPointer = InitializeNativeHost();
|
||||
if (!LoadAssemblyAndGetFunctionPointer)
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to initialize Runtime Host. Check logs for more details."));
|
||||
return false;
|
||||
}
|
||||
|
||||
const FString EntryPointClassName = TEXT("UnrealSharp.Plugins.Main, UnrealSharp.Plugins");
|
||||
const FString EntryPointFunctionName = TEXT("InitializeUnrealSharp");
|
||||
|
||||
const FString UnrealSharpLibraryAssembly = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetUnrealSharpPluginsPath());
|
||||
const FString UserWorkingDirectory = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetUserAssemblyDirectory());
|
||||
|
||||
FInitializeRuntimeHost InitializeUnrealSharp = nullptr;
|
||||
const int32 ErrorCode = LoadAssemblyAndGetFunctionPointer(PLATFORM_STRING(*UnrealSharpLibraryAssembly),
|
||||
PLATFORM_STRING(*EntryPointClassName),
|
||||
PLATFORM_STRING(*EntryPointFunctionName),
|
||||
UNMANAGEDCALLERSONLY_METHOD,
|
||||
nullptr,
|
||||
reinterpret_cast<void**>(&InitializeUnrealSharp));
|
||||
|
||||
if (ErrorCode != 0)
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Fatal, "Failed to load assembly: {0}", ErrorCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Entry point to C# to initialize UnrealSharp
|
||||
if (!InitializeUnrealSharp(*UserWorkingDirectory,
|
||||
*UnrealSharpLibraryAssembly,
|
||||
&ManagedPluginsCallbacks,
|
||||
(const void*)&FCSBindsManager::GetBoundFunction,
|
||||
&FCSManagedCallbacks::ManagedCallbacks))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to initialize UnrealSharp!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UCSManager::LoadRuntimeHost()
|
||||
{
|
||||
const FString RuntimeHostPath = FCSProcHelper::GetRuntimeHostPath();
|
||||
if (!FPaths::FileExists(RuntimeHostPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Couldn't find Hostfxr.dll"));
|
||||
return false;
|
||||
}
|
||||
|
||||
RuntimeHost = FPlatformProcess::GetDllHandle(*RuntimeHostPath);
|
||||
if (RuntimeHost == nullptr)
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Fatal, TEXT("Failed to get the RuntimeHost DLL handle!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
void* DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_dotnet_command_line"));
|
||||
Hostfxr_Initialize_For_Dotnet_Command_Line = static_cast<hostfxr_initialize_for_dotnet_command_line_fn>(DLLHandle);
|
||||
|
||||
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_runtime_config"));
|
||||
Hostfxr_Initialize_For_Runtime_Config = static_cast<hostfxr_initialize_for_runtime_config_fn>(DLLHandle);
|
||||
|
||||
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_get_runtime_delegate"));
|
||||
Hostfxr_Get_Runtime_Delegate = static_cast<hostfxr_get_runtime_delegate_fn>(DLLHandle);
|
||||
|
||||
DLLHandle = FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_close"));
|
||||
Hostfxr_Close = static_cast<hostfxr_close_fn>(DLLHandle);
|
||||
#else
|
||||
Hostfxr_Initialize_For_Dotnet_Command_Line = (hostfxr_initialize_for_dotnet_command_line_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_dotnet_command_line"));
|
||||
|
||||
Hostfxr_Initialize_For_Runtime_Config = (hostfxr_initialize_for_runtime_config_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_initialize_for_runtime_config"));
|
||||
|
||||
Hostfxr_Get_Runtime_Delegate = (hostfxr_get_runtime_delegate_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_get_runtime_delegate"));
|
||||
|
||||
Hostfxr_Close = (hostfxr_close_fn)FPlatformProcess::GetDllExport(RuntimeHost, TEXT("hostfxr_close"));
|
||||
#endif
|
||||
|
||||
return Hostfxr_Initialize_For_Dotnet_Command_Line && Hostfxr_Get_Runtime_Delegate && Hostfxr_Close && Hostfxr_Initialize_For_Runtime_Config;
|
||||
}
|
||||
|
||||
bool UCSManager::LoadAllUserAssemblies()
|
||||
{
|
||||
TArray<FString> UserAssemblyPaths;
|
||||
FCSProcHelper::GetAssemblyPathsByLoadOrder(UserAssemblyPaths, true);
|
||||
|
||||
if (UserAssemblyPaths.IsEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const FString& UserAssemblyPath : UserAssemblyPaths)
|
||||
{
|
||||
LoadAssemblyByPath(UserAssemblyPath);
|
||||
}
|
||||
|
||||
OnAssembliesLoaded.Broadcast();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UCSManager::NotifyUObjectDeleted(const UObjectBase* Object, int32 Index)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::NotifyUObjectDeleted);
|
||||
|
||||
TSharedPtr<FGCHandle> Handle;
|
||||
if (!ManagedObjectHandles.RemoveAndCopyValueByHash(Index, Index, Handle))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UCSAssembly* Assembly = FindOwningAssembly(Object->GetClass());
|
||||
if (!IsValid(Assembly))
|
||||
{
|
||||
FString ObjectName = Object->GetFName().ToString();
|
||||
FString ClassName = Object->GetClass()->GetFName().ToString();
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Failed to find owning assembly for object %s with class %s. Will cause managed memory leak."), *ObjectName, *ClassName);
|
||||
return;
|
||||
}
|
||||
|
||||
TSharedPtr<const FGCHandle> AssemblyHandle = Assembly->GetManagedAssemblyHandle();
|
||||
Handle->Dispose(AssemblyHandle->GetHandle());
|
||||
|
||||
TMap<uint32, TSharedPtr<FGCHandle>>* FoundHandles = ManagedInterfaceWrappers.FindByHash(Index, Index);
|
||||
if (FoundHandles == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &[Key, Value] : *FoundHandles)
|
||||
{
|
||||
Value->Dispose(AssemblyHandle->GetHandle());
|
||||
}
|
||||
|
||||
FoundHandles->Empty();
|
||||
ManagedInterfaceWrappers.Remove(Index);
|
||||
}
|
||||
|
||||
void UCSManager::OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason)
|
||||
{
|
||||
if (InModuleChangeReason != EModuleChangeReason::ModuleLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TryInitializeDynamicSubsystems();
|
||||
}
|
||||
|
||||
void UCSManager::TryInitializeDynamicSubsystems()
|
||||
{
|
||||
// Try to activate Editor/EngineSubsystems
|
||||
for (int32 i = PendingDynamicSubsystemClasses.Num() - 1; i >= 0; --i)
|
||||
{
|
||||
TSubclassOf<UDynamicSubsystem> SubsystemClass = PendingDynamicSubsystemClasses[i];
|
||||
if (!IsValid(SubsystemClass))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Warning, TEXT("Tried to activate an invalid dynamic subsystem class"));
|
||||
PendingDynamicSubsystemClasses.RemoveAt(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
FSubsystemCollectionBase::ActivateExternalSubsystem(SubsystemClass);
|
||||
|
||||
// Unfortunately no better way to check if the subsystems actually registered.
|
||||
{
|
||||
if (SubsystemClass->IsChildOf(UEngineSubsystem::StaticClass()))
|
||||
{
|
||||
if (IsValid(GEngine) && GEngine->GetEngineSubsystemBase(SubsystemClass.Get()))
|
||||
{
|
||||
PendingDynamicSubsystemClasses.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
#if WITH_EDITOR
|
||||
else if (SubsystemClass->IsChildOf(UEditorSubsystem::StaticClass()))
|
||||
{
|
||||
if (IsValid(GEditor) && GEditor->GetEditorSubsystemBase(SubsystemClass.Get()))
|
||||
{
|
||||
PendingDynamicSubsystemClasses.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load_assembly_and_get_function_pointer_fn UCSManager::InitializeNativeHost() const
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FString DotNetPath = FCSProcHelper::GetDotNetDirectory();
|
||||
#else
|
||||
FString DotNetPath = FCSProcHelper::GetPluginAssembliesPath();
|
||||
#endif
|
||||
|
||||
if (!FPaths::DirectoryExists(DotNetPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Dotnet directory does not exist at: %s"), *DotNetPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString RuntimeHostPath = FCSProcHelper::GetRuntimeHostPath();
|
||||
if (!FPaths::FileExists(RuntimeHostPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Runtime host path does not exist at: %s"), *RuntimeHostPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UE_LOG(LogUnrealSharp, Log, TEXT("DotNetPath: %s"), *DotNetPath);
|
||||
UE_LOG(LogUnrealSharp, Log, TEXT("RuntimeHostPath: %s"), *RuntimeHostPath);
|
||||
|
||||
hostfxr_initialize_parameters InitializeParameters;
|
||||
InitializeParameters.dotnet_root = PLATFORM_STRING(*DotNetPath);
|
||||
InitializeParameters.host_path = PLATFORM_STRING(*RuntimeHostPath);
|
||||
InitializeParameters.size = sizeof(hostfxr_initialize_parameters);
|
||||
|
||||
hostfxr_handle HostFXR_Handle = nullptr;
|
||||
int32 ErrorCode = 0;
|
||||
#if WITH_EDITOR
|
||||
FString RuntimeConfigPath = FCSProcHelper::GetRuntimeConfigPath();
|
||||
|
||||
if (!FPaths::FileExists(RuntimeConfigPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("No runtime config found"));
|
||||
return nullptr;
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
ErrorCode = Hostfxr_Initialize_For_Runtime_Config(PLATFORM_STRING(*RuntimeConfigPath), &InitializeParameters, &HostFXR_Handle);
|
||||
#else
|
||||
ErrorCode = Hostfxr_Initialize_For_Runtime_Config(PLATFORM_STRING(*RuntimeConfigPath), nullptr, &HostFXR_Handle);
|
||||
#endif
|
||||
|
||||
#else
|
||||
FString PluginAssemblyPath = FCSProcHelper::GetUnrealSharpPluginsPath();
|
||||
|
||||
if (!FPaths::FileExists(PluginAssemblyPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("UnrealSharp.Plugins.dll does not exist at: %s"), *PluginAssemblyPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector Args { PLATFORM_STRING(*PluginAssemblyPath) };
|
||||
|
||||
#if defined(_WIN32)
|
||||
ErrorCode = Hostfxr_Initialize_For_Dotnet_Command_Line(Args.size(), Args.data(), &InitializeParameters, &HostFXR_Handle);
|
||||
#else
|
||||
ErrorCode = Hostfxr_Initialize_For_Dotnet_Command_Line(Args.size(), const_cast<const char**>(Args.data()), &InitializeParameters, &HostFXR_Handle);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
if (ErrorCode != 0)
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("hostfxr_initialize_for_runtime_config failed with code: %d"), ErrorCode);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* LoadAssemblyAndGetFunctionPointer = nullptr;
|
||||
ErrorCode = Hostfxr_Get_Runtime_Delegate(HostFXR_Handle, hdt_load_assembly_and_get_function_pointer, &LoadAssemblyAndGetFunctionPointer);
|
||||
Hostfxr_Close(HostFXR_Handle);
|
||||
|
||||
if (ErrorCode != 0 || !LoadAssemblyAndGetFunctionPointer)
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("hostfxr_get_runtime_delegate failed with code: %d"), ErrorCode);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return (load_assembly_and_get_function_pointer_fn)LoadAssemblyAndGetFunctionPointer;
|
||||
}
|
||||
|
||||
UCSAssembly* UCSManager::LoadAssemblyByPath(const FString& AssemblyPath, bool bIsCollectible)
|
||||
{
|
||||
if (!FPaths::FileExists(AssemblyPath))
|
||||
{
|
||||
UE_LOG(LogUnrealSharp, Error, TEXT("Assembly path does not exist: %s"), *AssemblyPath);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FString AssemblyName = FPaths::GetBaseFilename(AssemblyPath);
|
||||
UCSAssembly* ExistingAssembly = FindAssembly(FName(*AssemblyName));
|
||||
|
||||
if (IsValid(ExistingAssembly) && ExistingAssembly->IsValidAssembly())
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Display, "Assembly {AssemblyName} is already loaded.", *AssemblyName);
|
||||
return ExistingAssembly;
|
||||
}
|
||||
|
||||
UCSAssembly* NewAssembly = NewObject<UCSAssembly>(this, *AssemblyName);
|
||||
NewAssembly->SetAssemblyPath(AssemblyPath);
|
||||
|
||||
LoadedAssemblies.Add(NewAssembly->GetAssemblyName(), NewAssembly);
|
||||
|
||||
if (!NewAssembly->LoadAssembly(bIsCollectible))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OnManagedAssemblyLoaded.Broadcast(NewAssembly->GetAssemblyName());
|
||||
|
||||
UE_LOGFMT(LogUnrealSharp, Display, "Successfully loaded AssemblyHandle with path {AssemblyPath}.", *AssemblyPath);
|
||||
return NewAssembly;
|
||||
}
|
||||
|
||||
UCSAssembly* UCSManager::LoadUserAssemblyByName(const FName AssemblyName, bool bIsCollectible)
|
||||
{
|
||||
FString AssemblyPath = FPaths::Combine(FCSProcHelper::GetUserAssemblyDirectory(), AssemblyName.ToString() + ".dll");
|
||||
return LoadAssemblyByPath(AssemblyPath, bIsCollectible);
|
||||
}
|
||||
|
||||
UCSAssembly* UCSManager::LoadPluginAssemblyByName(const FName AssemblyName, bool bIsCollectible)
|
||||
{
|
||||
FString AssemblyPath = FPaths::Combine(FCSProcHelper::GetPluginAssembliesPath(), AssemblyName.ToString() + ".dll");
|
||||
return LoadAssemblyByPath(AssemblyPath, bIsCollectible);
|
||||
}
|
||||
|
||||
UCSAssembly* UCSManager::FindOwningAssembly(UClass* Class)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
|
||||
|
||||
if (ICSManagedTypeInterface* ManagedType = FCSClassUtilities::GetManagedType(Class))
|
||||
{
|
||||
// Fast access to the owning assembly for managed types.
|
||||
return ManagedType->GetOwningAssembly();
|
||||
}
|
||||
|
||||
Class = FCSClassUtilities::GetFirstNativeClass(Class);
|
||||
uint32 ClassID = Class->GetUniqueID();
|
||||
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
|
||||
|
||||
if (IsValid(Assembly))
|
||||
{
|
||||
return Assembly;
|
||||
}
|
||||
|
||||
return FindOwningAssemblySlow(Class);
|
||||
}
|
||||
|
||||
UCSAssembly * UCSManager::FindOwningAssembly(UScriptStruct* Struct)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
|
||||
|
||||
if (const ICSManagedTypeInterface* ManagedType = Cast<ICSManagedTypeInterface>(Struct); ManagedType != nullptr)
|
||||
{
|
||||
// Fast access to the owning assembly for managed types.
|
||||
return ManagedType->GetOwningAssembly();
|
||||
}
|
||||
|
||||
if (const UUserDefinedStruct* UserStruct = Cast<UUserDefinedStruct>(Struct); UserStruct != nullptr)
|
||||
{
|
||||
// This is a Blueprint Struct and we can't use it
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 ClassID = Struct->GetUniqueID();
|
||||
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
|
||||
|
||||
if (IsValid(Assembly))
|
||||
{
|
||||
return Assembly;
|
||||
}
|
||||
|
||||
return FindOwningAssemblySlow(Struct);
|
||||
}
|
||||
|
||||
UCSAssembly* UCSManager::FindOwningAssembly(UEnum* Enum)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindOwningAssembly);
|
||||
|
||||
if (const ICSManagedTypeInterface* ManagedType = Cast<ICSManagedTypeInterface>(Enum); ManagedType != nullptr)
|
||||
{
|
||||
// Fast access to the owning assembly for managed types.
|
||||
return ManagedType->GetOwningAssembly();
|
||||
}
|
||||
|
||||
if (const UUserDefinedEnum* UserEnum = Cast<UUserDefinedEnum>(Enum); UserEnum != nullptr)
|
||||
{
|
||||
// This is a Blueprint Enum and we can't use it
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 ClassID = Enum->GetUniqueID();
|
||||
TObjectPtr<UCSAssembly> Assembly = NativeClassToAssemblyMap.FindOrAddByHash(ClassID, ClassID);
|
||||
|
||||
if (IsValid(Assembly))
|
||||
{
|
||||
return Assembly;
|
||||
}
|
||||
|
||||
return FindOwningAssemblySlow(Enum);
|
||||
}
|
||||
|
||||
|
||||
UCSAssembly* UCSManager::FindOwningAssemblySlow(UField *Field)
|
||||
{
|
||||
// Slow path for native classes. This runs once per new native class.
|
||||
const FCSFieldName ClassName = FCSFieldName(Field);
|
||||
|
||||
for (TPair<FName, TObjectPtr<UCSAssembly>>& LoadedAssembly : LoadedAssemblies)
|
||||
{
|
||||
if (TSharedPtr<FGCHandle> TypeHandle = LoadedAssembly.Value->TryFindTypeHandle(ClassName); !TypeHandle.IsValid() || TypeHandle->IsNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 FieldID = Field->GetUniqueID();
|
||||
NativeClassToAssemblyMap.AddByHash(FieldID, FieldID, LoadedAssembly.Value);
|
||||
return LoadedAssembly.Value;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FGCHandle UCSManager::FindManagedObject(const UObject* Object)
|
||||
{
|
||||
TRACE_CPUPROFILER_EVENT_SCOPE(UCSManager::FindManagedObject);
|
||||
|
||||
if (!IsValid(Object))
|
||||
{
|
||||
return FGCHandle::Null();
|
||||
}
|
||||
|
||||
uint32 ObjectID = Object->GetUniqueID();
|
||||
if (TSharedPtr<FGCHandle>* FoundHandle = ManagedObjectHandles.FindByHash(ObjectID, ObjectID))
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
// During full hot reload only the managed objects are GCd as we reload the assemblies.
|
||||
// So the C# counterpart can be invalid even if the handle can be found, so we need to create a new one.
|
||||
TSharedPtr<FGCHandle> HandlePtr = *FoundHandle;
|
||||
if (HandlePtr.IsValid() && !HandlePtr->IsNull())
|
||||
{
|
||||
return *HandlePtr;
|
||||
}
|
||||
#else
|
||||
return **FoundHandle;
|
||||
#endif
|
||||
}
|
||||
|
||||
// No existing handle found, we need to create a new managed object.
|
||||
UCSAssembly* OwningAssembly = FindOwningAssembly(Object->GetClass());
|
||||
if (!IsValid(OwningAssembly))
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Error, "Failed to find assembly for {0}", *Object->GetName());
|
||||
return FGCHandle::Null();
|
||||
}
|
||||
|
||||
return *OwningAssembly->CreateManagedObject(Object);
|
||||
}
|
||||
|
||||
FGCHandle UCSManager::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass)
|
||||
{
|
||||
if (!Object->GetClass()->ImplementsInterface(InterfaceClass))
|
||||
{
|
||||
return FGCHandle::Null();
|
||||
}
|
||||
|
||||
// No existing handle found, we need to create a new managed object.
|
||||
UCSAssembly* OwningAssembly = FindOwningAssembly(InterfaceClass);
|
||||
if (!IsValid(OwningAssembly))
|
||||
{
|
||||
UE_LOGFMT(LogUnrealSharp, Error, "Failed to find assembly for {0}", *InterfaceClass->GetName());
|
||||
return FGCHandle::Null();
|
||||
}
|
||||
|
||||
TSharedPtr<FGCHandle> FoundHandle = OwningAssembly->FindOrCreateManagedInterfaceWrapper(Object, InterfaceClass);
|
||||
if (!FoundHandle.IsValid())
|
||||
{
|
||||
return FGCHandle::Null();
|
||||
}
|
||||
|
||||
return *FoundHandle;
|
||||
}
|
||||
208
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.h
Normal file
208
Plugins/UnrealSharp/Source/UnrealSharpCore/CSManager.h
Normal file
@ -0,0 +1,208 @@
|
||||
#pragma once
|
||||
|
||||
#include <coreclr_delegates.h>
|
||||
#include <hostfxr.h>
|
||||
#include "CSAssembly.h"
|
||||
#include "CSManagedCallbacksCache.h"
|
||||
#include "CSManager.generated.h"
|
||||
|
||||
class UCSTypeBuilderManager;
|
||||
class UCSInterface;
|
||||
class UCSEnum;
|
||||
class UCSScriptStruct;
|
||||
class FUnrealSharpCoreModule;
|
||||
class UFunctionsExporter;
|
||||
struct FCSNamespace;
|
||||
struct FCSTypeReferenceMetaData;
|
||||
|
||||
struct FCSManagedPluginCallbacks
|
||||
{
|
||||
using LoadPluginCallback = FGCHandleIntPtr(__stdcall*)(const TCHAR*, bool);
|
||||
using UnloadPluginCallback = bool(__stdcall*)(const TCHAR*);
|
||||
|
||||
LoadPluginCallback LoadPlugin = nullptr;
|
||||
UnloadPluginCallback UnloadPlugin = nullptr;
|
||||
};
|
||||
|
||||
using FInitializeRuntimeHost = bool (*)(const TCHAR*, const TCHAR*, FCSManagedPluginCallbacks*, const void*, FCSManagedCallbacks::FManagedCallbacks*);
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnManagedAssemblyLoaded, const FName&);
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnManagedAssemblyUnloaded, const FName&);
|
||||
DECLARE_MULTICAST_DELEGATE(FOnAssembliesReloaded);
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FCSClassEvent, UCSClass*);
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FCSStructEvent, UCSScriptStruct*);
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FCSInterfaceEvent, UCSInterface*);
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FCSEnumEvent, UCSEnum*);
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UCSManager : public UObject, public FUObjectArray::FUObjectDeleteListener
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
|
||||
static UCSManager& GetOrCreate()
|
||||
{
|
||||
if (!Instance)
|
||||
{
|
||||
Instance = NewObject<UCSManager>(GetTransientPackage(), TEXT("CSManager"), RF_Public | RF_MarkAsRootSet);
|
||||
}
|
||||
|
||||
return *Instance;
|
||||
}
|
||||
|
||||
static UCSManager& Get() { return *Instance; }
|
||||
|
||||
// The outermost package for all managed packages. If namespace support is off, this is the only package that will be used.
|
||||
UPackage* GetGlobalManagedPackage() const { return GlobalManagedPackage; }
|
||||
UPackage* FindOrAddManagedPackage(FCSNamespace Namespace);
|
||||
|
||||
UCSAssembly* LoadAssemblyByPath(const FString& AssemblyPath, bool bIsCollectible = true);
|
||||
|
||||
// Load an assembly by name that exists in the ProjectRoot/Binaries/Managed folder
|
||||
UCSAssembly* LoadUserAssemblyByName(const FName AssemblyName, bool bIsCollectible = true);
|
||||
|
||||
// Load an assembly by name that exists in the UnrealSharp/Binaries/Managed folder
|
||||
UCSAssembly* LoadPluginAssemblyByName(const FName AssemblyName, bool bIsCollectible = true);
|
||||
|
||||
UCSAssembly* FindOwningAssembly(UClass* Class);
|
||||
|
||||
UCSAssembly* FindOwningAssembly(UScriptStruct* Struct);
|
||||
|
||||
UCSAssembly* FindOwningAssembly(UEnum* Enum);
|
||||
|
||||
UCSAssembly* FindAssembly(FName AssemblyName) const
|
||||
{
|
||||
return LoadedAssemblies.FindRef(AssemblyName);
|
||||
}
|
||||
|
||||
UCSAssembly* FindOrLoadAssembly(FName AssemblyName)
|
||||
{
|
||||
if (UCSAssembly* Assembly = FindAssembly(AssemblyName))
|
||||
{
|
||||
return Assembly;
|
||||
}
|
||||
|
||||
return LoadUserAssemblyByName(AssemblyName);
|
||||
}
|
||||
|
||||
FGCHandle FindManagedObject(const UObject* Object);
|
||||
FGCHandle FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* InterfaceClass);
|
||||
|
||||
void SetCurrentWorldContext(UObject* WorldContext) { CurrentWorldContext = WorldContext; }
|
||||
UObject* GetCurrentWorldContext() const { return CurrentWorldContext.Get(); }
|
||||
|
||||
const FCSManagedPluginCallbacks& GetManagedPluginsCallbacks() const { return ManagedPluginsCallbacks; }
|
||||
|
||||
FOnManagedAssemblyLoaded& OnManagedAssemblyLoadedEvent() { return OnManagedAssemblyLoaded; }
|
||||
FOnManagedAssemblyUnloaded& OnManagedAssemblyUnloadedEvent() { return OnManagedAssemblyUnloaded; }
|
||||
FOnAssembliesReloaded& OnAssembliesLoadedEvent() { return OnAssembliesLoaded; }
|
||||
|
||||
#if WITH_EDITOR
|
||||
FCSClassEvent& OnNewClassEvent() { return OnNewClass; }
|
||||
FCSStructEvent& OnNewStructEvent() { return OnNewStruct; }
|
||||
FCSInterfaceEvent& OnNewInterfaceEvent() { return OnNewInterface; }
|
||||
FCSEnumEvent& OnNewEnumEvent() { return OnNewEnum; }
|
||||
|
||||
FSimpleMulticastDelegate& OnProcessedPendingClassesEvent() { return OnProcessedPendingClasses; }
|
||||
#endif
|
||||
|
||||
void ForEachManagedPackage(const TFunction<void(UPackage*)>& Callback) const
|
||||
{
|
||||
for (UPackage* Package : AllPackages)
|
||||
{
|
||||
Callback(Package);
|
||||
}
|
||||
}
|
||||
void ForEachManagedField(const TFunction<void(UObject*)>& Callback) const;
|
||||
|
||||
bool IsManagedPackage(const UPackage* Package) const { return AllPackages.Contains(Package); }
|
||||
UPackage* GetPackage(const FCSNamespace Namespace);
|
||||
|
||||
bool IsManagedType(const UObject* Field) const { return IsManagedPackage(Field->GetOutermost()); }
|
||||
|
||||
bool IsLoadingAnyAssembly() const;
|
||||
|
||||
void AddDynamicSubsystemClass(TSubclassOf<UDynamicSubsystem> SubsystemClass);
|
||||
|
||||
UCSTypeBuilderManager* GetTypeBuilderManager() const { return TypeBuilderManager; }
|
||||
|
||||
private:
|
||||
|
||||
friend UCSAssembly;
|
||||
friend FUnrealSharpCoreModule;
|
||||
|
||||
void Initialize();
|
||||
static void Shutdown() { Instance = nullptr; }
|
||||
|
||||
load_assembly_and_get_function_pointer_fn InitializeNativeHost() const;
|
||||
|
||||
bool LoadRuntimeHost();
|
||||
bool InitializeDotNetRuntime();
|
||||
bool LoadAllUserAssemblies();
|
||||
|
||||
// UObjectArray listener interface
|
||||
virtual void NotifyUObjectDeleted(const UObjectBase* Object, int32 Index) override;
|
||||
virtual void OnUObjectArrayShutdown() override { GUObjectArray.RemoveUObjectDeleteListener(this); }
|
||||
void OnEnginePreExit() { GUObjectArray.RemoveUObjectDeleteListener(this); }
|
||||
// End of interface
|
||||
|
||||
void OnModulesChanged(FName InModuleName, EModuleChangeReason InModuleChangeReason);
|
||||
void TryInitializeDynamicSubsystems();
|
||||
|
||||
UCSAssembly* FindOwningAssemblySlow(UField* Field);
|
||||
|
||||
static UCSManager* Instance;
|
||||
|
||||
UPROPERTY()
|
||||
TArray<TObjectPtr<UPackage>> AllPackages;
|
||||
|
||||
UPROPERTY()
|
||||
TObjectPtr<UPackage> GlobalManagedPackage;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TArray<TSubclassOf<UDynamicSubsystem>> PendingDynamicSubsystemClasses;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UCSTypeBuilderManager> TypeBuilderManager;
|
||||
|
||||
// Handles to all active UObjects that has a C# counterpart. The key is the unique ID of the UObject.
|
||||
TMap<uint32, TSharedPtr<FGCHandle>> ManagedObjectHandles;
|
||||
|
||||
// Handles all active UObjects that have interface wrappers in C#. The primary key is the unique ID of the UObject.
|
||||
// The second key is the unique ID of the interface class.
|
||||
TMap<uint32, TMap<uint32, TSharedPtr<FGCHandle>>> ManagedInterfaceWrappers;
|
||||
|
||||
// Map to cache assemblies that native classes are associated with, for quick lookup.
|
||||
UPROPERTY()
|
||||
TMap<uint32, TObjectPtr<UCSAssembly>> NativeClassToAssemblyMap;
|
||||
|
||||
UPROPERTY()
|
||||
TMap<FName, TObjectPtr<UCSAssembly>> LoadedAssemblies;
|
||||
|
||||
TWeakObjectPtr<UObject> CurrentWorldContext;
|
||||
|
||||
FOnManagedAssemblyLoaded OnManagedAssemblyLoaded;
|
||||
FOnManagedAssemblyUnloaded OnManagedAssemblyUnloaded;
|
||||
FOnAssembliesReloaded OnAssembliesLoaded;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
FCSClassEvent OnNewClass;
|
||||
FCSStructEvent OnNewStruct;
|
||||
FCSInterfaceEvent OnNewInterface;
|
||||
FCSEnumEvent OnNewEnum;
|
||||
|
||||
FSimpleMulticastDelegate OnProcessedPendingClasses;
|
||||
#endif
|
||||
|
||||
FCSManagedPluginCallbacks ManagedPluginsCallbacks;
|
||||
|
||||
//.NET Core Host API
|
||||
hostfxr_initialize_for_dotnet_command_line_fn Hostfxr_Initialize_For_Dotnet_Command_Line = nullptr;
|
||||
hostfxr_initialize_for_runtime_config_fn Hostfxr_Initialize_For_Runtime_Config = nullptr;
|
||||
hostfxr_get_runtime_delegate_fn Hostfxr_Get_Runtime_Delegate = nullptr;
|
||||
hostfxr_close_fn Hostfxr_Close = nullptr;
|
||||
|
||||
void* RuntimeHost = nullptr;
|
||||
//End
|
||||
};
|
||||
35
Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.cpp
Normal file
35
Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include "CSNamespace.h"
|
||||
#include "CSManager.h"
|
||||
|
||||
FString FCSNamespace::GetLastNamespace() const
|
||||
{
|
||||
FString NamespaceString = Namespace.ToString();
|
||||
int32 LastDotIndex = NamespaceString.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
||||
|
||||
if (LastDotIndex == INDEX_NONE)
|
||||
{
|
||||
return NamespaceString;
|
||||
}
|
||||
|
||||
return NamespaceString.Right(NamespaceString.Len() - LastDotIndex - 1);
|
||||
}
|
||||
|
||||
bool FCSNamespace::GetParentNamespace(FCSNamespace& OutParent) const
|
||||
{
|
||||
FString NamespaceString = Namespace.ToString();
|
||||
int32 LastDotIndex = NamespaceString.Find(".", ESearchCase::CaseSensitive, ESearchDir::FromEnd);
|
||||
|
||||
if (LastDotIndex == INDEX_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FString ParentNamespace = NamespaceString.Left(LastDotIndex);
|
||||
OutParent = FCSNamespace(*ParentNamespace);
|
||||
return true;
|
||||
}
|
||||
|
||||
UPackage* FCSNamespace::GetPackage() const
|
||||
{
|
||||
return UCSManager::Get().FindOrAddManagedPackage(*this);
|
||||
}
|
||||
47
Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.h
Normal file
47
Plugins/UnrealSharp/Source/UnrealSharpCore/CSNamespace.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
struct FCSNamespace
|
||||
{
|
||||
FCSNamespace(FName InNamespace = NAME_None) : Namespace(InNamespace)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Get the namespace as a FName
|
||||
FName GetFName() const { return Namespace; }
|
||||
|
||||
// Get the namespace as a string
|
||||
FString GetName() const { return Namespace.ToString(); }
|
||||
|
||||
// Gets the name of the last part of the namespace. For example, if the namespace is "UnrealSharp.Core", this will return "Core".
|
||||
FString GetLastNamespace() const;
|
||||
|
||||
bool GetParentNamespace(FCSNamespace& OutParent) const;
|
||||
bool IsValid() const { return Namespace != NAME_None; }
|
||||
|
||||
UPackage* GetPackage() const;
|
||||
|
||||
UPackage* TryGetAsNativePackage() const
|
||||
{
|
||||
FString NativePackageName = FString::Printf(TEXT("/Script/%s"), *GetLastNamespace());
|
||||
return FindPackage(nullptr, *NativePackageName);
|
||||
}
|
||||
|
||||
FName GetPackageName() const { return *FString::Printf(TEXT("/Script/%s"), *Namespace.ToString()); }
|
||||
|
||||
static FCSNamespace Invalid() { return FCSNamespace(); }
|
||||
|
||||
bool operator == (const FCSNamespace& Other) const
|
||||
{
|
||||
return Namespace == Other.Namespace;
|
||||
}
|
||||
|
||||
friend uint32 GetTypeHash(const FCSNamespace& InNamespace)
|
||||
{
|
||||
return GetTypeHash(InNamespace.Namespace);
|
||||
}
|
||||
|
||||
private:
|
||||
FName Namespace;
|
||||
};
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSUnmanagedDataStore.generated.h"
|
||||
|
||||
USTRUCT()
|
||||
struct FUnmanagedDataStore
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
private:
|
||||
static constexpr size_t SmallStorageSize = 56;
|
||||
using FSmallStorage = std::array<std::byte, SmallStorageSize>;
|
||||
|
||||
struct FLargeStorageDeleter
|
||||
{
|
||||
void operator()(void* Ptr) const
|
||||
{
|
||||
FMemory::Free(Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
FUnmanagedDataStore() = default;
|
||||
|
||||
void CopyDataIn(const void* InData, const size_t Size)
|
||||
{
|
||||
if (Size <= SmallStorageSize)
|
||||
{
|
||||
Data.Emplace<FSmallStorage>();
|
||||
FMemory::Memcpy(Data.Get<FSmallStorage>().data(), InData, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Data.Emplace<TSharedPtr<void>>(FMemory::Malloc(Size), FLargeStorageDeleter());
|
||||
FMemory::Memcpy(Data.Get<TSharedPtr<void>>().Get(), InData, Size);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyDataOut(void* OutData, const size_t Size) const
|
||||
{
|
||||
if (Size <= SmallStorageSize)
|
||||
{
|
||||
FMemory::Memcpy(OutData, Data.Get<FSmallStorage>().data(), Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
FMemory::Memcpy(OutData, Data.Get<TSharedPtr<void>>().Get(), Size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
TVariant<FSmallStorage, TSharedPtr<void>> Data;
|
||||
|
||||
};
|
||||
@ -0,0 +1,55 @@
|
||||
#include "CSUnrealSharpSettings.h"
|
||||
|
||||
UCSUnrealSharpSettings::UCSUnrealSharpSettings()
|
||||
{
|
||||
CategoryName = "Plugins";
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UCSUnrealSharpSettings::PreEditChange(FProperty* PropertyAboutToChange)
|
||||
{
|
||||
Super::PreEditChange(PropertyAboutToChange);
|
||||
|
||||
if (PropertyAboutToChange->GetFName() == GET_MEMBER_NAME_CHECKED(UCSUnrealSharpSettings, bEnableNamespaceSupport))
|
||||
{
|
||||
OldValueOfNamespaceSupport = bEnableNamespaceSupport;
|
||||
}
|
||||
}
|
||||
|
||||
void UCSUnrealSharpSettings::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
if (PropertyChangedEvent.Property)
|
||||
{
|
||||
const FName PropertyName = PropertyChangedEvent.Property->GetFName();
|
||||
if (PropertyName == GET_MEMBER_NAME_CHECKED(UCSUnrealSharpSettings, bEnableNamespaceSupport))
|
||||
{
|
||||
bRecentlyChangedNamespaceSupport = true;
|
||||
|
||||
FText Message = FText::FromString(
|
||||
TEXT("Namespace support settings have been updated. A restart is required for the changes to take effect.\n\n"
|
||||
"WARNING: This experimental feature will break existing Blueprints derived from C# classes due to changes in the outermost package when restarting the engine.\n\n"
|
||||
"Press 'Cancel' to revert these changes.")
|
||||
);
|
||||
|
||||
if (FMessageDialog::Open(EAppMsgType::OkCancel, Message) == EAppReturnType::Cancel)
|
||||
{
|
||||
bEnableNamespaceSupport = OldValueOfNamespaceSupport;
|
||||
bRecentlyChangedNamespaceSupport = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool UCSUnrealSharpSettings::HasNamespaceSupport() const
|
||||
{
|
||||
if (bRecentlyChangedNamespaceSupport)
|
||||
{
|
||||
// Keep returning the old value until we have restarted the editor
|
||||
return OldValueOfNamespaceSupport;
|
||||
}
|
||||
|
||||
return bEnableNamespaceSupport;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/DeveloperSettings.h"
|
||||
#include "CSUnrealSharpSettings.generated.h"
|
||||
|
||||
UCLASS(config = UnrealSharp, defaultconfig, meta = (DisplayName = "UnrealSharp Settings"))
|
||||
class UNREALSHARPCORE_API UCSUnrealSharpSettings : public UDeveloperSettings
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UCSUnrealSharpSettings();
|
||||
|
||||
#if WITH_EDITOR
|
||||
// UObject interface
|
||||
virtual void PreEditChange(FProperty* PropertyAboutToChange) override;
|
||||
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
// End of UObject interface
|
||||
#endif
|
||||
|
||||
// Should we exit PIE when an exception is thrown in C#?
|
||||
UPROPERTY(EditDefaultsOnly, config, Category = "UnrealSharp | Debugging")
|
||||
bool bCrashOnException = true;
|
||||
|
||||
bool HasNamespaceSupport() const;
|
||||
|
||||
protected:
|
||||
|
||||
// Should we enable namespace support for generated types?
|
||||
// If false, all types will be generated in the global package and all types need to have unique names.
|
||||
// Currently destructive to the project if changed after BPs of C# types have been created.
|
||||
UPROPERTY(EditDefaultsOnly, config, Category = "UnrealSharp | Namespace", Experimental)
|
||||
bool bEnableNamespaceSupport = false;
|
||||
|
||||
bool bRecentlyChangedNamespaceSupport = false;
|
||||
bool OldValueOfNamespaceSupport = false;
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
#include "AsyncExporter.h"
|
||||
#include "CSManagedDelegate.h"
|
||||
|
||||
void UAsyncExporter::RunOnThread(TWeakObjectPtr<UObject> WorldContextObject, ENamedThreads::Type Thread, FGCHandleIntPtr DelegateHandle)
|
||||
{
|
||||
AsyncTask(Thread, [WorldContextObject, DelegateHandle]()
|
||||
{
|
||||
FCSManagedDelegate ManagedDelegate = FGCHandle(DelegateHandle, GCHandleType::StrongHandle);
|
||||
|
||||
if (!WorldContextObject.IsValid())
|
||||
{
|
||||
ManagedDelegate.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
ManagedDelegate.Invoke(WorldContextObject.Get());
|
||||
});
|
||||
}
|
||||
|
||||
int UAsyncExporter::GetCurrentNamedThread()
|
||||
{
|
||||
return FTaskGraphInterface::Get().GetCurrentThreadIfKnown();
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "Async/Async.h"
|
||||
#include "CSManagedGCHandle.h"
|
||||
#include "AsyncExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UAsyncExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RunOnThread(TWeakObjectPtr<UObject> WorldContextObject, ENamedThreads::Type Thread, FGCHandleIntPtr DelegateHandle);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int GetCurrentNamedThread();
|
||||
|
||||
};
|
||||
@ -0,0 +1,11 @@
|
||||
#include "CSTimerExtensions.h"
|
||||
|
||||
void UCSTimerExtensions::SetTimerForNextTick(FNextTickEvent NextTickEvent)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FFunctionGraphTask::CreateAndDispatchWhenReady([NextTickEvent]
|
||||
{
|
||||
GEditor->GetTimerManager()->SetTimerForNextTick(FTimerDelegate::CreateLambda(NextTickEvent));
|
||||
}, TStatId(), nullptr, ENamedThreads::GameThread);
|
||||
#endif
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "CSTimerExtensions.generated.h"
|
||||
|
||||
using FNextTickEvent = void(*)();
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UCSTimerExtensions : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void SetTimerForNextTick(FNextTickEvent NextTickEvent);
|
||||
};
|
||||
@ -0,0 +1,43 @@
|
||||
#include "FArrayPropertyExporter.h"
|
||||
|
||||
void UFArrayPropertyExporter::InitializeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.EmptyAndAddValues(Length);
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::EmptyArray(FArrayProperty* ArrayProperty, const void* ScriptArray)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.EmptyValues();
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::AddToArray(FArrayProperty* ArrayProperty, const void* ScriptArray)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.AddValue();
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::InsertInArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.InsertValues(index);
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::RemoveFromArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.RemoveValues(index);
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::ResizeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.Resize(Length);
|
||||
}
|
||||
|
||||
void UFArrayPropertyExporter::SwapValues(FArrayProperty* ArrayProperty, const void* ScriptArray, int indexA, int indexB)
|
||||
{
|
||||
FScriptArrayHelper Helper(ArrayProperty, ScriptArray);
|
||||
Helper.SwapValues(indexA, indexB);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FArrayPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFArrayPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void InitializeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void EmptyArray(FArrayProperty* ArrayProperty, const void* ScriptArray);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void AddToArray(FArrayProperty* ArrayProperty, const void* ScriptArray);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void InsertInArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RemoveFromArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int index);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void ResizeArray(FArrayProperty* ArrayProperty, const void* ScriptArray, int Length);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void SwapValues(FArrayProperty* ArrayProperty, const void* ScriptArray, int indexA, int indexB);
|
||||
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
#include "FBoolPropertyExporter.h"
|
||||
|
||||
bool UFBoolPropertyExporter::GetBitfieldValueFromProperty(uint8* NativeBuffer, FProperty* Property, int32 Offset)
|
||||
{
|
||||
// NativeBuffer won't necessarily correspond to a UObject. It might be the beginning of a native struct, for example.
|
||||
check(NativeBuffer);
|
||||
uint8* OffsetPointer = NativeBuffer + Offset;
|
||||
check(OffsetPointer == Property->ContainerPtrToValuePtr<uint8>(NativeBuffer));
|
||||
FBoolProperty* BoolProperty = CastFieldChecked<FBoolProperty>(Property);
|
||||
return BoolProperty->GetPropertyValue(OffsetPointer);
|
||||
}
|
||||
|
||||
void UFBoolPropertyExporter::SetBitfieldValueForProperty(uint8* NativeObject, FProperty* Property, int32 Offset, bool Value)
|
||||
{
|
||||
// NativeBuffer won't necessarily correspond to a UObject. It might be the beginning of a native struct, for example.
|
||||
check(NativeObject);
|
||||
uint8* OffsetPointer = NativeObject + Offset;
|
||||
check(OffsetPointer == Property->ContainerPtrToValuePtr<uint8>(NativeObject));
|
||||
const FBoolProperty* BoolProperty = CastFieldChecked<FBoolProperty>(Property);
|
||||
BoolProperty->SetPropertyValue(OffsetPointer, Value);
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FBoolPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFBoolPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool GetBitfieldValueFromProperty(uint8* NativeBuffer, FProperty* Property, int32 Offset);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void SetBitfieldValueForProperty(uint8* NativeObject, FProperty* Property, int32 Offset, bool Value);
|
||||
|
||||
};
|
||||
@ -0,0 +1,7 @@
|
||||
#include "FCSManagedCallbacksExporter.h"
|
||||
#include "CSManagedCallbacksCache.h"
|
||||
|
||||
FCSManagedCallbacks::FManagedCallbacks* UFCSManagedCallbacksExporter::GetManagedCallbacks()
|
||||
{
|
||||
return &FCSManagedCallbacks::ManagedCallbacks;
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "CSManagedCallbacksCache.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FCSManagedCallbacksExporter.generated.h"
|
||||
|
||||
class FCSManagedCallbacks;
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFCSManagedCallbacksExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FCSManagedCallbacks::FManagedCallbacks* GetManagedCallbacks();
|
||||
};
|
||||
@ -0,0 +1,23 @@
|
||||
#include "FCSManagerExporter.h"
|
||||
#include "UnrealSharpCore/CSManager.h"
|
||||
|
||||
void* UFCSManagerExporter::FindManagedObject(UObject* Object)
|
||||
{
|
||||
return UCSManager::Get().FindManagedObject(Object);
|
||||
}
|
||||
|
||||
void* UFCSManagerExporter::FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* NativeClass)
|
||||
{
|
||||
return UCSManager::Get().FindOrCreateManagedInterfaceWrapper(Object, NativeClass);
|
||||
}
|
||||
|
||||
void* UFCSManagerExporter::GetCurrentWorldContext()
|
||||
{
|
||||
return UCSManager::Get().GetCurrentWorldContext();
|
||||
}
|
||||
|
||||
void* UFCSManagerExporter::GetCurrentWorldPtr()
|
||||
{
|
||||
UObject* WorldContext = UCSManager::Get().GetCurrentWorldContext();
|
||||
return GEngine->GetWorldFromContextObject(WorldContext, EGetWorldErrorMode::ReturnNull);
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FCSManagerExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFCSManagerExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* FindManagedObject(UObject* Object);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* FindOrCreateManagedInterfaceWrapper(UObject* Object, UClass* NativeClass);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetCurrentWorldContext();
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetCurrentWorldPtr();
|
||||
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
#include "FCSTypeRegistryExporter.h"
|
||||
|
||||
void UFCSTypeRegistryExporter::RegisterClassToFilePath(const UTF16CHAR* ClassName, const UTF16CHAR* FilePath)
|
||||
{
|
||||
//FCSTypeRegistry::Get().RegisterClassToFilePath(ClassName, FilePath);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FCSTypeRegistryExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UFCSTypeRegistryExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RegisterClassToFilePath(const UTF16CHAR* ClassName, const UTF16CHAR* FilePath);
|
||||
|
||||
};
|
||||
@ -0,0 +1,30 @@
|
||||
#include "FEditorDelegatesExporter.h"
|
||||
|
||||
void UFEditorDelegatesExporter::BindEndPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
*DelegateHandle = FEditorDelegates::EndPIE.AddLambda(Delegate);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UFEditorDelegatesExporter::BindStartPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
*DelegateHandle = FEditorDelegates::BeginPIE.AddLambda(Delegate);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UFEditorDelegatesExporter::UnbindStartPIE(FDelegateHandle DelegateHandle)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FEditorDelegates::BeginPIE.Remove(DelegateHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UFEditorDelegatesExporter::UnbindEndPIE(FDelegateHandle DelegateHandle)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
FEditorDelegates::EndPIE.Remove(DelegateHandle);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FEditorDelegatesExporter.generated.h"
|
||||
|
||||
using FPIEEvent = void(*)(bool);
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFEditorDelegatesExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void BindEndPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void BindStartPIE(FPIEEvent Delegate, FDelegateHandle* DelegateHandle);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void UnbindEndPIE(FDelegateHandle DelegateHandle);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void UnbindStartPIE(FDelegateHandle DelegateHandle);
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "FFieldPathExporter.h"
|
||||
|
||||
bool UFFieldPathExporter::IsValid(const TFieldPath<FField>& FieldPath)
|
||||
{
|
||||
return FieldPath != nullptr;
|
||||
}
|
||||
|
||||
bool UFFieldPathExporter::IsStale(const FFieldPath& FieldPath)
|
||||
{
|
||||
return FieldPath.IsStale();
|
||||
}
|
||||
|
||||
void UFFieldPathExporter::FieldPathToString(const FFieldPath& FieldPath, FString* OutString)
|
||||
{
|
||||
*OutString = FieldPath.ToString();
|
||||
}
|
||||
|
||||
bool UFFieldPathExporter::FieldPathsEqual(const FFieldPath& A, const FFieldPath& B)
|
||||
{
|
||||
return A == B;
|
||||
}
|
||||
|
||||
int32 UFFieldPathExporter::GetFieldPathHashCode(const FFieldPath& FieldPath)
|
||||
{
|
||||
// GetHashCode returns a signed integer in C#, but GetTypeHash returns an unsigned integer, thus
|
||||
// the cast is necessary
|
||||
return static_cast<int32>(GetTypeHash(FieldPath));
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FFieldPathExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFFieldPathExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsValid(const TFieldPath<FField>& FieldPath);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsStale(const FFieldPath& FieldPath);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void FieldPathToString(const FFieldPath& FieldPath, FString* OutString);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool FieldPathsEqual(const FFieldPath& A, const FFieldPath& B);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetFieldPathHashCode(const FFieldPath& FieldPath);
|
||||
};
|
||||
@ -0,0 +1,38 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "FInstancedStructExporter.h"
|
||||
|
||||
#include "StructUtils/InstancedStruct.h"
|
||||
|
||||
const UScriptStruct* UFInstancedStructExporter::GetNativeStruct(const FInstancedStruct& Struct)
|
||||
{
|
||||
check(&Struct != nullptr);
|
||||
return Struct.GetScriptStruct();
|
||||
}
|
||||
|
||||
void UFInstancedStructExporter::NativeInit(FInstancedStruct& Struct)
|
||||
{
|
||||
std::construct_at(&Struct);
|
||||
}
|
||||
|
||||
void UFInstancedStructExporter::NativeCopy(FInstancedStruct& Dest, const FInstancedStruct& Src)
|
||||
{
|
||||
std::construct_at(&Dest, Src);
|
||||
}
|
||||
|
||||
void UFInstancedStructExporter::NativeDestroy(FInstancedStruct& Struct)
|
||||
{
|
||||
std::destroy_at(&Struct);
|
||||
}
|
||||
|
||||
void UFInstancedStructExporter::InitializeAs(FInstancedStruct& Struct, const UScriptStruct* ScriptStruct, const uint8* StructData)
|
||||
{
|
||||
check(ScriptStruct != nullptr);
|
||||
Struct.InitializeAs(ScriptStruct, StructData);
|
||||
}
|
||||
|
||||
const uint8* UFInstancedStructExporter::GetMemory(const FInstancedStruct& Struct)
|
||||
{
|
||||
return Struct.GetMemory();
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FInstancedStructExporter.generated.h"
|
||||
|
||||
struct FInstancedStruct;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFInstancedStructExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static const UScriptStruct* GetNativeStruct(const FInstancedStruct& Struct);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void NativeInit(FInstancedStruct& Struct);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void NativeCopy(FInstancedStruct& Dest, const FInstancedStruct& Src);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void NativeDestroy(FInstancedStruct& Struct);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void InitializeAs(FInstancedStruct& Struct, const UScriptStruct* ScriptStruct, const uint8* StructData);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static const uint8* GetMemory(const FInstancedStruct& Struct);
|
||||
};
|
||||
@ -0,0 +1,11 @@
|
||||
#include "FMapPropertyExporter.h"
|
||||
|
||||
void* UFMapPropertyExporter::GetKey(FMapProperty* MapProperty)
|
||||
{
|
||||
return MapProperty->KeyProp;
|
||||
}
|
||||
|
||||
void* UFMapPropertyExporter::GetValue(FMapProperty* MapProperty)
|
||||
{
|
||||
return MapProperty->ValueProp;
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FMapPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFMapPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetKey(FMapProperty* MapProperty);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetValue(FMapProperty* MapProperty);
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
#include "FMatrixExporter.h"
|
||||
|
||||
void UFMatrixExporter::FromRotator(FMatrix* Matrix, const FRotator Rotator)
|
||||
{
|
||||
*Matrix = Rotator.Quaternion().ToMatrix();
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FMatrixExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFMatrixExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void FromRotator(FMatrix* Matrix, const FRotator Rotator);
|
||||
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
#include "FMsgExporter.h"
|
||||
|
||||
void UFMsgExporter::Log(const UTF16CHAR* ManagedCategoryName, ELogVerbosity::Type Verbosity, const UTF16CHAR* ManagedMessage)
|
||||
{
|
||||
FString Message = FString(ManagedMessage);
|
||||
FName CategoryName = FName(ManagedCategoryName);
|
||||
|
||||
FMsg::Logf(nullptr, 0, CategoryName, Verbosity, TEXT("%s"), *Message);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FMsgExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFMsgExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void Log(const UTF16CHAR* ManagedCategoryName, ELogVerbosity::Type Verbosity, const UTF16CHAR* ManagedMessage);
|
||||
|
||||
};
|
||||
@ -0,0 +1,64 @@
|
||||
#include "FMulticastDelegatePropertyExporter.h"
|
||||
|
||||
void UFMulticastDelegatePropertyExporter::AddDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName)
|
||||
{
|
||||
FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName);
|
||||
DelegateProperty->AddDelegate(NewScriptDelegate, nullptr, Delegate);
|
||||
}
|
||||
|
||||
bool UFMulticastDelegatePropertyExporter::IsBound(FMulticastScriptDelegate* Delegate)
|
||||
{
|
||||
return Delegate->IsBound();
|
||||
}
|
||||
|
||||
void UFMulticastDelegatePropertyExporter::ToString(FMulticastScriptDelegate* Delegate, FString* OutString)
|
||||
{
|
||||
*OutString = Delegate->ToString<UObject>();
|
||||
}
|
||||
|
||||
void UFMulticastDelegatePropertyExporter::RemoveDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName)
|
||||
{
|
||||
FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName);
|
||||
DelegateProperty->RemoveDelegate(NewScriptDelegate, nullptr, Delegate);
|
||||
}
|
||||
|
||||
void UFMulticastDelegatePropertyExporter::ClearDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate)
|
||||
{
|
||||
DelegateProperty->ClearDelegate(nullptr, Delegate);
|
||||
}
|
||||
|
||||
void UFMulticastDelegatePropertyExporter::BroadcastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, void* Parameters)
|
||||
{
|
||||
Delegate = TryGetSparseMulticastDelegate(DelegateProperty, Delegate);
|
||||
Delegate->ProcessMulticastDelegate<UObject>(Parameters);
|
||||
}
|
||||
|
||||
bool UFMulticastDelegatePropertyExporter::ContainsDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName)
|
||||
{
|
||||
FScriptDelegate NewScriptDelegate = MakeScriptDelegate(Target, FunctionName);
|
||||
Delegate = TryGetSparseMulticastDelegate(DelegateProperty, Delegate);
|
||||
return Delegate->Contains(NewScriptDelegate);
|
||||
}
|
||||
|
||||
void* UFMulticastDelegatePropertyExporter::GetSignatureFunction(FMulticastDelegateProperty* DelegateProperty)
|
||||
{
|
||||
return DelegateProperty->SignatureFunction;
|
||||
}
|
||||
|
||||
FScriptDelegate UFMulticastDelegatePropertyExporter::MakeScriptDelegate(UObject* Target, const char* FunctionName)
|
||||
{
|
||||
FScriptDelegate NewDelegate;
|
||||
NewDelegate.BindUFunction(Target, FunctionName);
|
||||
return NewDelegate;
|
||||
}
|
||||
|
||||
const FMulticastScriptDelegate* UFMulticastDelegatePropertyExporter::TryGetSparseMulticastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate)
|
||||
{
|
||||
// If the delegate is a sparse delegate, we need to get the multicast delegate from FSparseDelegate wrapper.
|
||||
if (DelegateProperty->IsA<FMulticastSparseDelegateProperty>())
|
||||
{
|
||||
Delegate = DelegateProperty->GetMulticastDelegate(Delegate);
|
||||
}
|
||||
|
||||
return Delegate;
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FMulticastDelegatePropertyExporter.generated.h"
|
||||
|
||||
struct Interop_FScriptDelegate
|
||||
{
|
||||
UObject* Object;
|
||||
FName Name;
|
||||
|
||||
FScriptDelegate ToFScriptDelegate() const
|
||||
{
|
||||
FScriptDelegate NewScriptDelegate;
|
||||
NewScriptDelegate.BindUFunction(Object, Name);
|
||||
return NewScriptDelegate;
|
||||
}
|
||||
};
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFMulticastDelegatePropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void AddDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsBound(FMulticastScriptDelegate* Delegate);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void ToString(FMulticastScriptDelegate* Delegate, FString* OutString);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RemoveDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void ClearDelegate(FMulticastDelegateProperty* DelegateProperty, FMulticastScriptDelegate* Delegate);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void BroadcastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, void* Parameters);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool ContainsDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate, UObject* Target, const char* FunctionName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetSignatureFunction(FMulticastDelegateProperty* DelegateProperty);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FScriptDelegate MakeScriptDelegate(UObject* Target, const char* FunctionName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static const FMulticastScriptDelegate* TryGetSparseMulticastDelegate(FMulticastDelegateProperty* DelegateProperty, const FMulticastScriptDelegate* Delegate);
|
||||
|
||||
};
|
||||
@ -0,0 +1,17 @@
|
||||
#include "FNameExporter.h"
|
||||
|
||||
void UFNameExporter::NameToString(FName Name, FString* OutString)
|
||||
{
|
||||
Name.ToString(*OutString);
|
||||
}
|
||||
|
||||
void UFNameExporter::StringToName(FName* Name, const UTF16CHAR* String, int32 Length)
|
||||
{
|
||||
*Name = FName(TStringView(String, Length));
|
||||
}
|
||||
|
||||
bool UFNameExporter::IsValid(FName Name)
|
||||
{
|
||||
bool bIsValid = Name.IsValid();
|
||||
return bIsValid;
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FNameExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFNameExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void NameToString(FName Name, FString* OutString);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void StringToName(FName* Name, const UTF16CHAR* String, int32 Length);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsValid(FName Name);
|
||||
|
||||
};
|
||||
@ -0,0 +1,62 @@
|
||||
#include "FOptionalPropertyExporter.h"
|
||||
#include "UObject/PropertyOptional.h"
|
||||
|
||||
bool UFOptionalPropertyExporter::IsSet(const FOptionalProperty* OptionalProperty, const void* ScriptValue)
|
||||
{
|
||||
return OptionalProperty->IsSet(ScriptValue);
|
||||
}
|
||||
|
||||
void* UFOptionalPropertyExporter::MarkSetAndGetInitializedValuePointerToReplace(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->MarkSetAndGetInitializedValuePointerToReplace(Data);
|
||||
}
|
||||
|
||||
void UFOptionalPropertyExporter::MarkUnset(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->MarkUnset(Data);
|
||||
}
|
||||
|
||||
const void* UFOptionalPropertyExporter::GetValuePointerForRead(const FOptionalProperty* OptionalProperty, const void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForRead(Data);
|
||||
}
|
||||
|
||||
void* UFOptionalPropertyExporter::GetValuePointerForReplace(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForReplace(Data);
|
||||
}
|
||||
|
||||
const void* UFOptionalPropertyExporter::GetValuePointerForReadIfSet(const FOptionalProperty* OptionalProperty, const void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForReadIfSet(Data);
|
||||
}
|
||||
|
||||
void* UFOptionalPropertyExporter::GetValuePointerForReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForReplaceIfSet(Data);
|
||||
}
|
||||
|
||||
void* UFOptionalPropertyExporter::GetValuePointerForReadOrReplace(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForReadOrReplace(Data);
|
||||
}
|
||||
|
||||
void* UFOptionalPropertyExporter::GetValuePointerForReadOrReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
return OptionalProperty->GetValuePointerForReadOrReplaceIfSet(Data);
|
||||
}
|
||||
|
||||
int32 UFOptionalPropertyExporter::CalcSize(const FOptionalProperty* OptionalProperty)
|
||||
{
|
||||
#if ENGINE_MINOR_VERSION >= 5
|
||||
// Do we really need this? StaticLink should do this.
|
||||
return OptionalProperty->CalcSize();
|
||||
#else
|
||||
return OptionalProperty->GetSize();
|
||||
#endif
|
||||
}
|
||||
|
||||
void UFOptionalPropertyExporter::DestructInstance(const FOptionalProperty* OptionalProperty, void* Data)
|
||||
{
|
||||
OptionalProperty->DestroyValueInternal(Data);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FOptionalPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFOptionalPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsSet(const FOptionalProperty* OptionalProperty, const void* ScriptValue);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* MarkSetAndGetInitializedValuePointerToReplace(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void MarkUnset(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static const void* GetValuePointerForRead(const FOptionalProperty* OptionalProperty, const void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetValuePointerForReplace(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static const void* GetValuePointerForReadIfSet(const FOptionalProperty* OptionalProperty, const void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetValuePointerForReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetValuePointerForReadOrReplace(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetValuePointerForReadOrReplaceIfSet(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 CalcSize(const FOptionalProperty* OptionalProperty);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void DestructInstance(const FOptionalProperty* OptionalProperty, void* Data);
|
||||
};
|
||||
@ -0,0 +1,106 @@
|
||||
#include "FPropertyExporter.h"
|
||||
|
||||
FProperty* UFPropertyExporter::GetNativePropertyFromName(UStruct* Struct, const char* PropertyName)
|
||||
{
|
||||
FProperty* Property = FindFProperty<FProperty>(Struct, PropertyName);
|
||||
return Property;
|
||||
}
|
||||
|
||||
int32 UFPropertyExporter::GetPropertyOffset(FProperty* Property)
|
||||
{
|
||||
return Property->GetOffset_ForInternal();
|
||||
}
|
||||
|
||||
int32 UFPropertyExporter::GetSize(FProperty* Property)
|
||||
{
|
||||
return Property->GetSize();
|
||||
}
|
||||
|
||||
int32 UFPropertyExporter::GetArrayDim(FProperty* Property)
|
||||
{
|
||||
return Property->ArrayDim;
|
||||
}
|
||||
|
||||
void UFPropertyExporter::DestroyValue(FProperty* Property, void* Value)
|
||||
{
|
||||
Property->DestroyValue(Value);
|
||||
}
|
||||
|
||||
void UFPropertyExporter::DestroyValue_InContainer(FProperty* Property, void* Value)
|
||||
{
|
||||
Property->DestroyValue_InContainer(Value);
|
||||
}
|
||||
|
||||
void UFPropertyExporter::InitializeValue(FProperty* Property, void* Value)
|
||||
{
|
||||
Property->InitializeValue(Value);
|
||||
}
|
||||
|
||||
bool UFPropertyExporter::Identical(const FProperty* Property, void* ValueA, void* ValueB)
|
||||
{
|
||||
bool bIsIdentical = Property->Identical(ValueA, ValueB);
|
||||
return bIsIdentical;
|
||||
}
|
||||
|
||||
void UFPropertyExporter::GetInnerFields(FProperty* SetProperty, TArray<FField*>* OutFields)
|
||||
{
|
||||
SetProperty->GetInnerFields(*OutFields);
|
||||
}
|
||||
|
||||
uint32 UFPropertyExporter::GetValueTypeHash(FProperty* Property, void* Source)
|
||||
{
|
||||
return Property->GetValueTypeHash(Source);
|
||||
}
|
||||
|
||||
bool UFPropertyExporter::HasAnyPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck)
|
||||
{
|
||||
return Property->HasAnyPropertyFlags(FlagsToCheck);
|
||||
}
|
||||
|
||||
bool UFPropertyExporter::HasAllPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck)
|
||||
{
|
||||
return Property->HasAllPropertyFlags(FlagsToCheck);
|
||||
}
|
||||
|
||||
void UFPropertyExporter::CopySingleValue(FProperty* Property, void* Dest, void* Src)
|
||||
{
|
||||
Property->CopySingleValue(Dest, Src);
|
||||
}
|
||||
|
||||
void UFPropertyExporter::GetValue_InContainer(FProperty* Property, void* Container, void* OutValue)
|
||||
{
|
||||
Property->GetValue_InContainer(Container, OutValue);
|
||||
}
|
||||
|
||||
void UFPropertyExporter::SetValue_InContainer(FProperty* Property, void* Container, void* Value)
|
||||
{
|
||||
Property->SetValue_InContainer(Container, Value);
|
||||
}
|
||||
|
||||
uint8 UFPropertyExporter::GetBoolPropertyFieldMaskFromName(UStruct* InStruct, const char* InPropertyName)
|
||||
{
|
||||
FBoolProperty* Property = FindFProperty<FBoolProperty>(InStruct, InPropertyName);
|
||||
if (!Property)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Property->GetFieldMask();
|
||||
}
|
||||
|
||||
int32 UFPropertyExporter::GetPropertyOffsetFromName(UStruct* InStruct, const char* InPropertyName)
|
||||
{
|
||||
FProperty* FoundProperty = GetNativePropertyFromName(InStruct, InPropertyName);
|
||||
if (!FoundProperty)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return GetPropertyOffset(FoundProperty);
|
||||
}
|
||||
|
||||
int32 UFPropertyExporter::GetPropertyArrayDimFromName(UStruct* InStruct, const char* PropertyName)
|
||||
{
|
||||
FProperty* Property = GetNativePropertyFromName(InStruct, PropertyName);
|
||||
return GetArrayDim(Property);
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FProperty* GetNativePropertyFromName(UStruct* Struct, const char* PropertyName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetPropertyOffsetFromName(UStruct* InStruct, const char* InPropertyName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetPropertyArrayDimFromName(UStruct* InStruct, const char* PropertyName);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetPropertyOffset(FProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetSize(FProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 GetArrayDim(FProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void DestroyValue(FProperty* Property, void* Value);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void DestroyValue_InContainer(FProperty* Property, void* Value);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void InitializeValue(FProperty* Property, void* Value);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool Identical(const FProperty* Property, void* ValueA, void* ValueB);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void GetInnerFields(FProperty* SetProperty, TArray<FField*>* OutFields);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static uint32 GetValueTypeHash(FProperty* Property, void* Source);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool HasAnyPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool HasAllPropertyFlags(FProperty* Property, EPropertyFlags FlagsToCheck);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void CopySingleValue(FProperty* Property, void* Dest, void* Src);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void GetValue_InContainer(FProperty* Property, void* Container, void* OutValue);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void SetValue_InContainer(FProperty* Property, void* Container, void* Value);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static uint8 GetBoolPropertyFieldMaskFromName(UStruct* InStruct, const char* InPropertyName);
|
||||
};
|
||||
@ -0,0 +1,37 @@
|
||||
#include "FRandomStreamExporter.h"
|
||||
|
||||
void UFRandomStreamExporter::GenerateNewSeed(FRandomStream* RandomStream)
|
||||
{
|
||||
RandomStream->GenerateNewSeed();
|
||||
}
|
||||
|
||||
float UFRandomStreamExporter::GetFraction(FRandomStream* RandomStream)
|
||||
{
|
||||
return RandomStream->GetFraction();
|
||||
}
|
||||
|
||||
uint32 UFRandomStreamExporter::GetUnsignedInt(FRandomStream* RandomStream)
|
||||
{
|
||||
return RandomStream->GetUnsignedInt();
|
||||
}
|
||||
|
||||
FVector UFRandomStreamExporter::GetUnitVector(FRandomStream* RandomStream)
|
||||
{
|
||||
return RandomStream->GetUnitVector();
|
||||
}
|
||||
|
||||
int UFRandomStreamExporter::RandRange(FRandomStream* RandomStream, int32 Min, int32 Max)
|
||||
{
|
||||
return RandomStream->RandRange(Min, Max);
|
||||
}
|
||||
|
||||
FVector UFRandomStreamExporter::VRandCone(FRandomStream* RandomStream, FVector Dir, float ConeHalfAngleRad)
|
||||
{
|
||||
return RandomStream->VRandCone(Dir, ConeHalfAngleRad);
|
||||
}
|
||||
|
||||
FVector UFRandomStreamExporter::VRandCone2(FRandomStream* RandomStream, FVector Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad)
|
||||
{
|
||||
return RandomStream->VRandCone(Dir, HorizontalConeHalfAngleRad, VerticalConeHalfAngleRad);
|
||||
}
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FRandomStreamExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFRandomStreamExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void GenerateNewSeed(FRandomStream* RandomStream);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static float GetFraction(FRandomStream* RandomStream);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static uint32 GetUnsignedInt(FRandomStream* RandomStream);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FVector GetUnitVector(FRandomStream* RandomStream);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int RandRange(FRandomStream* RandomStream, int32 Min, int32 Max);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FVector VRandCone(FRandomStream* RandomStream, FVector Dir, float ConeHalfAngleRad);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static FVector VRandCone2(FRandomStream* RandomStream, FVector Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad);
|
||||
|
||||
};
|
||||
@ -0,0 +1,8 @@
|
||||
#include "FRotatorExporter.h"
|
||||
|
||||
void UFRotatorExporter::FromMatrix(FRotator* Rotator, const FMatrix& Matrix)
|
||||
{
|
||||
*Rotator = Matrix.Rotator();
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FRotatorExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFRotatorExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void FromMatrix(FRotator* Rotator, const FMatrix& Matrix);
|
||||
|
||||
};
|
||||
@ -0,0 +1,21 @@
|
||||
#include "FScriptArrayExporter.h"
|
||||
|
||||
void* UFScriptArrayExporter::GetData(FScriptArray* Instance)
|
||||
{
|
||||
return Instance->GetData();
|
||||
}
|
||||
|
||||
bool UFScriptArrayExporter::IsValidIndex(FScriptArray* Instance, int32 i)
|
||||
{
|
||||
return Instance->IsValidIndex(i);
|
||||
}
|
||||
|
||||
int UFScriptArrayExporter::Num(FScriptArray* Instance)
|
||||
{
|
||||
return Instance->Num();
|
||||
}
|
||||
|
||||
void UFScriptArrayExporter::Destroy(FScriptArray* Instance)
|
||||
{
|
||||
Instance->~FScriptArray();
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FScriptArrayExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFScriptArrayExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetData(FScriptArray* Instance);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsValidIndex(FScriptArray* Instance, int32 i);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int Num(FScriptArray* Instance);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void Destroy(FScriptArray* Instance);
|
||||
|
||||
};
|
||||
@ -0,0 +1,11 @@
|
||||
#include "FScriptDelegateExporter.h"
|
||||
|
||||
void UFScriptDelegateExporter::BroadcastDelegate(FScriptDelegate* Delegate, void* Params)
|
||||
{
|
||||
Delegate->ProcessDelegate<UObject>(Params);
|
||||
}
|
||||
|
||||
bool UFScriptDelegateExporter::IsBound(FScriptDelegate* Delegate)
|
||||
{
|
||||
return Delegate->IsBound();
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FScriptDelegateExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFScriptDelegateExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void BroadcastDelegate(FScriptDelegate* Delegate, void* Params);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsBound(FScriptDelegate* Delegate);
|
||||
|
||||
};
|
||||
@ -0,0 +1,65 @@
|
||||
#include "FScriptMapHelperExporter.h"
|
||||
|
||||
void UFScriptMapHelperExporter::AddPair(FMapProperty* MapProperty, const void* Address, const void* Key, const void* Value)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
Helper.AddPair(Key, Value);
|
||||
}
|
||||
|
||||
void* UFScriptMapHelperExporter::FindOrAdd(FMapProperty* MapProperty, const void* Address, const void* Key)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
return Helper.FindOrAdd(Key);
|
||||
}
|
||||
|
||||
int UFScriptMapHelperExporter::Num(FMapProperty* MapProperty, const void* Address)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
return Helper.Num();
|
||||
}
|
||||
|
||||
int UFScriptMapHelperExporter::FindMapPairIndexFromHash(FMapProperty* MapProperty, const void* Address, const void* Key)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
#if ENGINE_MINOR_VERSION >= 4
|
||||
return Helper.FindMapPairIndexFromHash(Key);
|
||||
#else
|
||||
return Helper.FindMapIndexWithKey(Key);
|
||||
#endif
|
||||
}
|
||||
|
||||
void UFScriptMapHelperExporter::RemoveIndex(FMapProperty* MapProperty, const void* Address, int Index)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
Helper.RemoveAt(Index);
|
||||
}
|
||||
|
||||
void UFScriptMapHelperExporter::EmptyValues(FMapProperty* MapProperty, const void* Address)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
Helper.EmptyValues();
|
||||
}
|
||||
|
||||
void UFScriptMapHelperExporter::Remove(FMapProperty* MapProperty, const void* Address, const void* Key)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
Helper.RemovePair(Key);
|
||||
}
|
||||
|
||||
bool UFScriptMapHelperExporter::IsValidIndex(FMapProperty* MapProperty, const void* Address, int Index)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
return Helper.IsValidIndex(Index);
|
||||
}
|
||||
|
||||
int UFScriptMapHelperExporter::GetMaxIndex(FMapProperty* MapProperty, const void* Address)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
return Helper.GetMaxIndex();
|
||||
}
|
||||
|
||||
void* UFScriptMapHelperExporter::GetPairPtr(FMapProperty* MapProperty, const void* Address, int Index)
|
||||
{
|
||||
FScriptMapHelper Helper(MapProperty, Address);
|
||||
return Helper.GetPairPtr(Index);
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FScriptMapHelperExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFScriptMapHelperExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void AddPair(FMapProperty* MapProperty, const void* Address, const void* Key, const void* Value);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* FindOrAdd(FMapProperty* MapProperty, const void* Address, const void* Key);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int Num(FMapProperty* MapProperty, const void* Address);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int FindMapPairIndexFromHash(FMapProperty* MapProperty, const void* Address, const void* Key);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RemoveIndex(FMapProperty* MapProperty, const void* Address, int Index);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void EmptyValues(FMapProperty* MapProperty, const void* Address);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void Remove(FMapProperty* MapProperty, const void* Address, const void* Key);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsValidIndex(FMapProperty* MapProperty, const void* Address, int Index);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int GetMaxIndex(FMapProperty* MapProperty, const void* Address);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetPairPtr(FMapProperty* MapProperty, const void* Address, int Index);
|
||||
|
||||
};
|
||||
@ -0,0 +1,52 @@
|
||||
#include "FScriptSetExporter.h"
|
||||
|
||||
bool UFScriptSetExporter::IsValidIndex(FScriptSet* ScriptSet, int32 Index)
|
||||
{
|
||||
return ScriptSet->IsValidIndex(Index);
|
||||
}
|
||||
|
||||
int UFScriptSetExporter::Num(FScriptSet* ScriptSet)
|
||||
{
|
||||
int Num = ScriptSet->Num();
|
||||
return Num;
|
||||
}
|
||||
|
||||
int UFScriptSetExporter::GetMaxIndex(FScriptSet* ScriptSet)
|
||||
{
|
||||
return ScriptSet->GetMaxIndex();
|
||||
}
|
||||
|
||||
void* UFScriptSetExporter::GetData(int Index, FScriptSet* ScriptSet, FSetProperty* Property)
|
||||
{
|
||||
return ScriptSet->GetData(Index, Property->SetLayout);
|
||||
}
|
||||
|
||||
void UFScriptSetExporter::Empty(int Slack, FScriptSet* ScriptSet, FSetProperty* Property)
|
||||
{
|
||||
return ScriptSet->Empty(Slack, Property->SetLayout);
|
||||
}
|
||||
|
||||
void UFScriptSetExporter::RemoveAt(int Index, FScriptSet* ScriptSet, FSetProperty* Property)
|
||||
{
|
||||
return ScriptSet->RemoveAt(Index, Property->SetLayout);
|
||||
}
|
||||
|
||||
int UFScriptSetExporter::AddUninitialized(FScriptSet* ScriptSet, FSetProperty* Property)
|
||||
{
|
||||
return ScriptSet->AddUninitialized(Property->SetLayout);
|
||||
}
|
||||
|
||||
void UFScriptSetExporter::Add(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element,FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn, FDestructFn DestructFn)
|
||||
{
|
||||
ScriptSet->Add(Element, Property->SetLayout, GetKeyHash, EqualityFn, ConstructFn, DestructFn);
|
||||
}
|
||||
|
||||
int32 UFScriptSetExporter::FindOrAdd(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn)
|
||||
{
|
||||
return ScriptSet->FindOrAdd(Element, Property->SetLayout, GetKeyHash, EqualityFn, ConstructFn);
|
||||
}
|
||||
|
||||
int UFScriptSetExporter::FindIndex(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn)
|
||||
{
|
||||
return ScriptSet->FindIndex(Element, Property->SetLayout, GetKeyHash, EqualityFn);
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FScriptSetExporter.generated.h"
|
||||
|
||||
using FGetKeyHash = uint32(*)(const void*);
|
||||
using FEqualityFn = bool(*)(const void*, const void*);
|
||||
using FConstructFn = void(*)(void*);
|
||||
using FDestructFn = void(*)(void*);
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFScriptSetExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static bool IsValidIndex(FScriptSet* ScriptSet, int32 Index);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int Num(FScriptSet* ScriptSet);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int GetMaxIndex(FScriptSet* ScriptSet);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetData(int Index, FScriptSet* ScriptSet, FSetProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void Empty(int Slack, FScriptSet* ScriptSet, FSetProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void RemoveAt(int Index, FScriptSet* ScriptSet, FSetProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int AddUninitialized(FScriptSet* ScriptSet, FSetProperty* Property);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void Add(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn, FDestructFn DestructFn);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int32 FindOrAdd(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn, FConstructFn ConstructFn);
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static int FindIndex(FScriptSet* ScriptSet, FSetProperty* Property, const void* Element, FGetKeyHash GetKeyHash, FEqualityFn EqualityFn);
|
||||
|
||||
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
#include "FSetPropertyExporter.h"
|
||||
|
||||
void* UFSetPropertyExporter::GetElement(FSetProperty* Property)
|
||||
{
|
||||
return Property->ElementProp;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FSetPropertyExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFSetPropertyExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* GetElement(FSetProperty* Property);
|
||||
};
|
||||
@ -0,0 +1,13 @@
|
||||
#include "FSoftObjectPtrExporter.h"
|
||||
#include "UnrealSharpCore/CSManager.h"
|
||||
|
||||
void* UFSoftObjectPtrExporter::LoadSynchronous(const TSoftObjectPtr<UObject>* SoftObjectPtr)
|
||||
{
|
||||
if (SoftObjectPtr->IsNull())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UObject* LoadedObject = SoftObjectPtr->LoadSynchronous();
|
||||
return UCSManager::Get().FindManagedObject(LoadedObject);
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FSoftObjectPtrExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFSoftObjectPtrExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void* LoadSynchronous(const TSoftObjectPtr<UObject>* SoftObjectPtr);
|
||||
|
||||
};
|
||||
@ -0,0 +1,6 @@
|
||||
#include "FStringExporter.h"
|
||||
|
||||
void UFStringExporter::MarshalToNativeString(FString* String, TCHAR* ManagedString)
|
||||
{
|
||||
*String = ManagedString;
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "FStringExporter.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFStringExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UNREALSHARP_FUNCTION()
|
||||
static void MarshalToNativeString(FString* String, TCHAR* ManagedString);
|
||||
|
||||
};
|
||||
@ -0,0 +1,9 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "FSubsystemCollectionBaseRefExporter.h"
|
||||
|
||||
USubsystem* UFSubsystemCollectionBaseRefExporter::InitializeDependency(FSubsystemCollectionBase* Collection, UClass* SubsystemClass)
|
||||
{
|
||||
return Collection->InitializeDependency(SubsystemClass);
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CSBindsManager.h"
|
||||
#include "UObject/Object.h"
|
||||
#include "FSubsystemCollectionBaseRefExporter.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class UNREALSHARPCORE_API UFSubsystemCollectionBaseRefExporter : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UNREALSHARP_FUNCTION()
|
||||
static USubsystem* InitializeDependency(FSubsystemCollectionBase* Collection, UClass* SubsystemClass);
|
||||
};
|
||||
@ -0,0 +1,66 @@
|
||||
#include "FTextExporter.h"
|
||||
|
||||
const TCHAR* UFTextExporter::ToString(FText* Text)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return *Text->ToString();
|
||||
}
|
||||
|
||||
void UFTextExporter::ToStringView(FText* Text, const TCHAR*& OutString, int32& OutLength)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
OutString = nullptr;
|
||||
OutLength = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const FString& AsString = Text->ToString();
|
||||
OutString = *AsString;
|
||||
OutLength = AsString.Len();
|
||||
}
|
||||
|
||||
void UFTextExporter::FromString(FText* Text, const char* String)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*Text = Text->FromString(String);
|
||||
}
|
||||
|
||||
void UFTextExporter::FromStringView(FText* Text, const TCHAR* String, int32 Length)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*Text = Text->FromStringView(FStringView(String, Length));
|
||||
}
|
||||
|
||||
void UFTextExporter::FromName(FText* Text, FName Name)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*Text = Text->FromName(Name);
|
||||
}
|
||||
|
||||
void UFTextExporter::CreateEmptyText(FText* Text)
|
||||
{
|
||||
if (!Text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
*Text = FText::GetEmpty();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user