Last active
June 14, 2024 01:47
-
-
Save iDevelopThings/e7fb05d78b14c12197f4ec4e26db65a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Reflection/FunctionCallUtil.h" | |
FFunctionCallParamInfo::FFunctionCallParamInfo() = default; | |
FFunctionCallParamInfo::FFunctionCallParamInfo(bool InIsReturnParam, const FString& InName, int InIndex, FProperty* InProperty): | |
IsReturnParam(InIsReturnParam), | |
Name(InName), | |
Index(InIndex), | |
Property(InProperty) {} | |
FFunctionCall::FFunctionCall() { | |
Init(); | |
} | |
FFunctionCall::FFunctionCall(UObject* InObject, const FString& FunctionName): | |
Object(InObject), | |
Function(InObject->FindFunction(*FunctionName)) { | |
Init(); | |
} | |
FFunctionCall::FFunctionCall(UObject* InObject, UFunction* InFunction): | |
Object(InObject), | |
Function(InFunction) { | |
Init(); | |
} | |
FFunctionCall& FFunctionCall::PushParam(const FString& ParamName, const void* Value) { | |
// if (!ParamsBuffer) return *this; | |
if (!ParamMap.Contains(ParamName)) { | |
UE_GAMELOG(LogCommonGame, Error, "Param %s not found", *ParamName); | |
return *this; | |
} | |
SetParamValue(ParamMap[ParamName], Value); | |
return *this; | |
} | |
FFunctionCall& FFunctionCall::PushParam(const int Index, const void* Value) { | |
// if (!ParamsBuffer) return *this; | |
if (!ParamArray.IsValidIndex(Index)) { | |
UE_GAMELOG(LogCommonGame, Error, "Param index %d out of range", Index); | |
return *this; | |
} | |
SetParamValue(ParamArray[Index], Value); | |
return *this; | |
} | |
void FFunctionCall::Call() { | |
if (!Function) { | |
UE_GAMELOG(LogCommonGame, Error, "Function not found"); | |
return; | |
} | |
Object->ProcessEvent(Function, ParamsBuffer.GetData()); | |
} | |
void FFunctionCall::Init() { | |
if (!Function) { | |
UE_GAMELOG(LogCommonGame, Error, "Function not found"); | |
return; | |
} | |
if (Function->ParmsSize > 0) { | |
ParamsBuffer.AddUninitialized(Function->ParmsSize); | |
Function->InitializeStruct(ParamsBuffer.GetData()); | |
int Index = 0; | |
auto PropIterator = TFieldRange<FProperty>( | |
Function, | |
static_cast<EFieldIterationFlags>(EFieldIteratorFlags::ExcludeSuper | EFieldIteratorFlags::ExcludeDeprecated | EFieldIteratorFlags::ExcludeInterfaces) | |
); | |
for (FProperty* Property : PropIterator) { | |
if (!Property->HasAnyPropertyFlags(CPF_Parm)) { | |
continue; | |
} | |
FFunctionCallParamInfo ParamInfo; | |
ParamInfo.Name = Property->GetName(); | |
ParamInfo.Index = Index; | |
ParamInfo.Property = Property; | |
if (Property->PropertyFlags & CPF_ReturnParm) { | |
ParamInfo.IsReturnParam = true; | |
ReturnParam = ParamInfo; | |
} | |
ParamMap.Add(ParamInfo.Name, ParamInfo); | |
ParamArray.Add(ParamInfo); | |
if (!Property->HasAnyPropertyFlags(CPF_ZeroConstructor)) { | |
Property->InitializeValue_InContainer(ParamsBuffer.GetData()); | |
} | |
Index++; | |
} | |
} | |
} | |
bool FFunctionCall::SetParamValue(FFunctionCallParamInfo& Param, const void* Value) { | |
if (!Param.Property) { | |
return false; | |
} | |
Param.Property->SetValue_InContainer(ParamsBuffer.GetData(), Value); | |
return true; | |
} | |
void FFunctionCall::CopyValueToBuffer(FProperty* Param, const void* Value) { | |
} | |
bool operator==(const FFunctionCallParamInfo& Lhs, const FFunctionCallParamInfo& RHS) { return Lhs.Property == RHS.Property; } | |
bool operator!=(const FFunctionCallParamInfo& Lhs, const FFunctionCallParamInfo& RHS) { return !(Lhs == RHS); } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "CoreMinimal.h" | |
#include "CommonGame.h" | |
#include "LoggerMacros.h" | |
#include "Traits/IsVoidType.h" | |
#include "UObject/UnrealTypePrivate.h" | |
struct COMMONGAME_API FFunctionCallParamInfo | |
{ | |
bool IsReturnParam = false; | |
FString Name = ""; | |
int Index = -1; | |
FProperty* Property = nullptr; | |
FFunctionCallParamInfo(); | |
FFunctionCallParamInfo(bool InIsReturnParam, const FString& InName, int InIndex, FProperty* InProperty); | |
friend bool operator==(const FFunctionCallParamInfo& Lhs, const FFunctionCallParamInfo& RHS); | |
friend bool operator!=(const FFunctionCallParamInfo& Lhs, const FFunctionCallParamInfo& RHS); | |
}; | |
struct COMMONGAME_API FFunctionCall | |
{ | |
private: | |
TArray<uint8> ParamsBuffer; | |
FFunctionCallParamInfo ReturnParam; | |
TMap<FString, FFunctionCallParamInfo> ParamMap; | |
TArray<FFunctionCallParamInfo> ParamArray; | |
public: | |
UObject* Object = nullptr; | |
UFunction* Function = nullptr; | |
FFunctionCall(); | |
FFunctionCall(UObject* InObject, const FString& FunctionName); | |
FFunctionCall(UObject* InObject, UFunction* InFunction); | |
FFunctionCall& PushParam(const FString& ParamName, const void* Value); | |
FFunctionCall& PushParam(const int Index, const void* Value); | |
template <typename T> | |
FFunctionCall& PushParamIfExists(T* ParamValue) { | |
// If T is a UObject | |
if constexpr (TIsDerivedFrom<T, UObject>::IsDerived) { | |
UClass* TClass = T::StaticClass(); | |
for (FFunctionCallParamInfo& ParamInfo : ParamArray) { | |
FProperty* Property = ParamInfo.Property; | |
if (FObjectPropertyBase* ObjProperty = CastField<FObjectPropertyBase>(Property)) { | |
if (ObjProperty->PropertyClass == TClass) { | |
SetParamValue(ParamInfo, ParamValue); | |
break; | |
} | |
} | |
} | |
} else if constexpr (TIsDerivedFrom<T, UScriptStruct>::IsDerived) { | |
UScriptStruct* TClass = T::StaticStruct(); | |
for (FFunctionCallParamInfo& ParamInfo : ParamArray) { | |
FProperty* Property = ParamInfo.Property; | |
if (FStructProperty* StructProperty = CastField<FStructProperty>(Property)) { | |
if (StructProperty->Struct == TClass) { | |
SetParamValue(ParamInfo, ParamValue); | |
break; | |
} | |
} | |
} | |
} | |
return *this; | |
} | |
void Call(); | |
template <typename T> | |
T Call() { | |
if (!Function) { | |
UE_GAMELOG(LogCommonGame, Error, "Function not found"); | |
return T(); | |
} | |
T ReturnValue; | |
FFrame Stack(Object, Function, ParamsBuffer.GetData(), nullptr, Function->ChildProperties); | |
Function->Invoke(Object, Stack, &ReturnValue); | |
return ReturnValue; | |
} | |
private: | |
void Init(); | |
bool SetParamValue(FFunctionCallParamInfo& Param, const void* Value); | |
void CopyValueToBuffer(FProperty* Param, const void* Value); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
UFunction* DrawPaneFn = ObjClass->FindFunctionByName(TEXT("DrawDebugPane"), EIncludeSuperFlag::IncludeSuper) | |
void UDebugPanesManager::CallPaneDrawFunc(UObject* Obj, UFunction* DrawPaneFn, UDebugPanesManager* Manager, UDebugPane* Pane, UCanvas* Canvas, APlayerController* PlayerController) { | |
FFunctionCall FnCall(Obj, DrawPaneFn); | |
FnCall.PushParam(0, &Manager); | |
FnCall.PushParam(1, &Pane); | |
FnCall.PushParam(2, &Canvas); | |
FnCall.PushParam(3, &PlayerController); | |
FnCall.Call(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment