This commit is contained in:
2025-02-10 00:44:11 +08:00
parent ece733c0e5
commit 1e0c4b8d8c
1640 changed files with 1628924 additions and 0 deletions
@@ -0,0 +1,740 @@
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#include "FunctionTranslator.h"
#include "V8Utils.h"
#include "Misc/DefaultValueHelper.h"
#include <mutex>
static TMap<FName, TMap<FName, TMap<FName, FString>>> ParamDefaultMetas;
static TMap<FName, TMap<FName, FString>>* PC = nullptr;
static TMap<FName, FString>* PF = nullptr;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 2
UE_DISABLE_OPTIMIZATION
#else
PRAGMA_DISABLE_OPTIMIZATION
#endif
static void ParamDefaultMetasInit()
{
// PC = &ParamDefaultMetas.Add(TEXT("MainObject"));
// PF = &PC->Add(TEXT("DefaultTest"));
// PF->Add(TEXT("Str"), TEXT("i am default"));
// PF->Add(TEXT("I"), TEXT("10"));
// PF->Add(TEXT("Vec"), TEXT("1.100000,2.200000,3.300000"));
#include "InitParamDefaultMetas.inl"
return;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 2
UE_ENABLE_OPTIMIZATION
#else
PRAGMA_ENABLE_OPTIMIZATION
#endif
std::once_flag ParamDefaultMetasInitFlag;
TMap<FName, FString>* GetParamDefaultMetaFor(UFunction* InFunction)
{
std::call_once(ParamDefaultMetasInitFlag, ParamDefaultMetasInit);
UClass* OuterClass = InFunction->GetOuterUClass();
auto ClassParamDefaultMeta = ParamDefaultMetas.Find(OuterClass->GetFName());
if (ClassParamDefaultMeta)
{
return ClassParamDefaultMeta->Find(InFunction->GetFName());
}
return nullptr;
}
namespace PUERTS_NAMESPACE
{
static const int ARG_ARRAY_SIZE = 8;
#if defined(USE_GLOBAL_PARAMS_BUFFER)
// Global Buffer, Not thread safe
static void* Buffer = nullptr;
static int BufferSize = 0;
static void RequireBuffer(int RequireSize)
{
if (RequireSize > BufferSize)
{
if (Buffer)
FMemory::Free(Buffer);
Buffer = FMemory::Malloc(RequireSize, 16);
BufferSize = RequireSize;
}
}
class GlobalBufferAutoRelease
{
public:
~GlobalBufferAutoRelease()
{
if (Buffer)
FMemory::Free(Buffer);
Buffer = nullptr;
BufferSize = 0;
}
};
static GlobalBufferAutoRelease Dummy;
#endif
FFunctionTranslator::FFunctionTranslator(UFunction* InFunction, bool IsDelegate)
{
Init(InFunction, IsDelegate);
}
void FFunctionTranslator::Init(UFunction* InFunction, bool IsDelegate)
{
check(InFunction);
Function = InFunction;
#if WITH_EDITOR
FunctionName = Function->GetFName();
#endif
ParamsBufferSize = InFunction->PropertiesSize > InFunction->ParmsSize ? InFunction->PropertiesSize : InFunction->ParmsSize;
#if defined(USE_GLOBAL_PARAMS_BUFFER)
RequireBuffer(ParamsBufferSize);
#endif
if (IsDelegate)
{
IsInterfaceFunction = false;
IsStatic = false;
}
else
{
UClass* OuterClass = InFunction->GetOuterUClass();
IsInterfaceFunction = (OuterClass->HasAnyClassFlags(CLASS_Interface) && OuterClass != UInterface::StaticClass());
IsStatic = InFunction->HasAnyFunctionFlags(FUNC_Static);
}
Arguments.clear();
SkipWorldContextInArg0 = false;
for (TFieldIterator<PropertyMacro> It(InFunction); It && (It->PropertyFlags & CPF_Parm); ++It)
{
PropertyMacro* Property = *It;
static const FName WorldContextPinName(TEXT("__WorldContext"));
if (IsStatic && !InFunction->IsNative() && Property->GetFName() == WorldContextPinName && Arguments.size() == 0)
{
SkipWorldContextInArg0 = true;
;
}
if (Property->HasAnyPropertyFlags(CPF_ReturnParm))
{
Return = FPropertyTranslator::Create(Property);
}
else
{
Arguments.push_back(FPropertyTranslator::Create(Property));
}
}
ArgumentDefaultValues = nullptr;
if (!IsDelegate)
{
TMap<FName, FString>* MetaMap = GetParamDefaultMetaFor(InFunction);
if (MetaMap)
{
for (TFieldIterator<PropertyMacro> ParamIt(InFunction); ParamIt; ++ParamIt)
{
auto Property = *ParamIt;
if (Property->PropertyFlags & CPF_Parm)
{
if (!(Property->PropertyFlags & CPF_ReturnParm))
{
// const FName MetadataCppDefaultValueKey(*(FString(TEXT("CPP_Default_")) + Property->GetName()));
FString* DefaultValuePtr = nullptr;
DefaultValuePtr = MetaMap->Find(Property->GetFName());
if (DefaultValuePtr && !DefaultValuePtr->IsEmpty())
{
// UE_LOG(LogTemp, Warning, TEXT("Meta %s %s"), *Property->GetFName().ToString(), **DefaultValuePtr);
if (!ArgumentDefaultValues)
{
ArgumentDefaultValues = FMemory::Malloc(ParamsBufferSize, 16);
InFunction->InitializeStruct(ArgumentDefaultValues);
}
void* PropValuePtr = Property->ContainerPtrToValuePtr<void>(ArgumentDefaultValues);
if (const StructPropertyMacro* StructProp = CastFieldMacro<StructPropertyMacro>(Property))
{
if (StructProp->Struct == TBaseStructure<FVector>::Get())
{
FVector* Vector = (FVector*) PropValuePtr;
FDefaultValueHelper::ParseVector(**DefaultValuePtr, *Vector);
continue;
}
else if (StructProp->Struct == TBaseStructure<FVector2D>::Get())
{
FVector2D* Vector2D = (FVector2D*) PropValuePtr;
FDefaultValueHelper::ParseVector2D(**DefaultValuePtr, *Vector2D);
continue;
}
else if (StructProp->Struct == TBaseStructure<FRotator>::Get())
{
FRotator* Rotator = (FRotator*) PropValuePtr;
FDefaultValueHelper::ParseRotator(**DefaultValuePtr, *Rotator);
continue;
}
else if (StructProp->Struct == TBaseStructure<FColor>::Get())
{
FColor* Color = (FColor*) PropValuePtr;
FDefaultValueHelper::ParseColor(**DefaultValuePtr, *Color);
continue;
}
else if (StructProp->Struct == TBaseStructure<FLinearColor>::Get())
{
FLinearColor* LinearColor = (FLinearColor*) PropValuePtr;
LinearColor->InitFromString(**DefaultValuePtr);
continue;
}
}
#if ENGINE_MINOR_VERSION > 0 && ENGINE_MAJOR_VERSION > 4
Property->ImportText_Direct(**DefaultValuePtr, PropValuePtr, nullptr, PPF_None);
#else
Property->ImportText(**DefaultValuePtr, PropValuePtr, PPF_None, nullptr);
#endif
}
}
}
}
}
}
}
v8::Local<v8::FunctionTemplate> FFunctionTranslator::ToFunctionTemplate(v8::Isolate* Isolate)
{
return v8::FunctionTemplate::New(Isolate, Call, v8::External::New(Isolate, this));
}
void FFunctionTranslator::Call(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
FFunctionTranslator* This = static_cast<FFunctionTranslator*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
This->Call(Isolate, Context, Info);
}
void FFunctionTranslator::Call(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
UObject* CallObject = IsStatic ? BindObject.Get() : FV8Utils::GetUObject(Info.Holder());
if (!CallObject)
{
if (IsStatic) //延时初始化
{
CallObject = Function->GetOuterUClass()->GetDefaultObject();
BindObject = CallObject;
}
if (!CallObject)
{
FV8Utils::ThrowException(Isolate, "access a null object");
return;
}
}
if (FV8Utils::IsReleasedPtr(CallObject))
{
FV8Utils::ThrowException(Isolate, "access a invalid object");
return;
}
TWeakObjectPtr<UFunction> CallFunction =
!IsInterfaceFunction ? Function : (CallObject->GetClass()->FindFunctionByName(Function->GetFName()));
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
#if WITH_EDITOR
if (!CallFunction.IsValid())
{
CallFunction = CallObject->GetClass()->FindFunctionByName(FunctionName);
Init(CallFunction.Get(), false);
}
#endif
auto CallFunctionPtr = CallFunction.Get();
if ((Function->FunctionFlags & FUNC_Native) && !(Function->FunctionFlags & FUNC_Net) &&
!CallFunctionPtr->HasAnyFunctionFlags(FUNC_UbergraphFunction))
{
FastCall(Isolate, Context, Info, CallObject, CallFunctionPtr, Params);
}
else
{
SlowCall(Isolate, Context, Info, CallObject, CallFunctionPtr, Params);
}
}
void FFunctionTranslator::SlowCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, UObject* CallObject, UFunction* CallFunction, void* Params)
{
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
}
if (!Call_ProcessParams(Isolate, Context, Info, Params, 0))
{
return;
}
CallObject->UObject::ProcessEvent(CallFunction, Params);
Call_ProcessReturnAndOutParams(Isolate, Context, Info, Params, 0);
}
void FFunctionTranslator::FastCall(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, UObject* CallObject, UFunction* CallFunction, void* Params)
{
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
if (Return)
{
Return->Property->InitializeValue_InContainer(Params);
}
}
FFrame NewStack(CallObject, CallFunction, Params, nullptr,
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
Function->ChildProperties
#else
Function->Children
#endif
);
checkSlow(NewStack.Locals || Function->ParmsSize == 0);
FOutParmRec** LastOut = &NewStack.OutParms;
int Index = 0;
for (TFieldIterator<PropertyMacro> It(CallFunction); It && (It->PropertyFlags & CPF_Parm); ++It)
{
PropertyMacro* Property = *It;
FOutParmRec* Out = nullptr;
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
CA_SUPPRESS(6263)
Out = (FOutParmRec*) FMemory_Alloca(sizeof(FOutParmRec));
Out->Property = Property;
if (*LastOut)
{
(*LastOut)->NextOutParm = Out;
LastOut = &(*LastOut)->NextOutParm;
}
else
{
*LastOut = Out;
}
}
if (Property->HasAnyPropertyFlags(CPF_ReturnParm))
{
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
Out->PropAddr = Property->ContainerPtrToValuePtr<uint8>(Params);
}
continue;
}
if (UNLIKELY(ArgumentDefaultValues && Info[Index]->IsUndefined()))
{
Property->CopyCompleteValue_InContainer(Params, ArgumentDefaultValues);
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
Out->PropAddr = Property->ContainerPtrToValuePtr<uint8>(Params);
}
}
else
{
Property->InitializeValue_InContainer(Params);
if (Property->HasAnyPropertyFlags(CPF_OutParm))
{
if (!Arguments[Index]->JsToUEFastInContainer(
Isolate, Context, Info[Index], Params, reinterpret_cast<void**>(&(Out->PropAddr))))
{
return;
}
}
else
{
if (!Arguments[Index]->JsToUEInContainer(Isolate, Context, Info[Index], Params, false))
{
return;
}
}
}
++Index;
}
if (CallFunction->HasAnyFunctionFlags(FUNC_HasOutParms))
{
if (*LastOut)
{
(*LastOut)->NextOutParm = NULL;
}
}
const bool bHasReturnParam = CallFunction->ReturnValueOffset != MAX_uint16;
uint8* ReturnValueAddress = bHasReturnParam ? ((uint8*) Params + CallFunction->ReturnValueOffset) : nullptr;
CallFunction->Invoke(CallObject, NewStack, ReturnValueAddress);
if (Return)
{
Info.GetReturnValue().Set(Return->UEToJsInContainer(Isolate, Context, Params));
Return->Property->DestroyValue_InContainer(Params);
}
LastOut = &NewStack.OutParms;
for (int i = 0; i < Arguments.size(); ++i)
{
auto PropertyFlags = Arguments[i]->Property->PropertyFlags;
if (PropertyFlags & CPF_OutParm)
{
if ((PropertyFlags & CPF_Parm) && (!(PropertyFlags & CPF_ConstParm)) && (!(PropertyFlags & CPF_ReturnParm)))
{
if ((*LastOut)->PropAddr >= (uint8*) Params && (*LastOut)->PropAddr < ((uint8*) Params + ParamsBufferSize))
{
Arguments[i]->UEOutToJsInContainer(Isolate, Context, Info[i], Params, false);
}
else
{
LastOut = &(*LastOut)->NextOutParm;
continue;
}
}
LastOut = &(*LastOut)->NextOutParm;
}
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
void FFunctionTranslator::Call(v8::Isolate* Isolate, v8::Local<v8::Context>& Context,
const v8::FunctionCallbackInfo<v8::Value>& Info, std::function<void(void*)> OnCall)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
FMemory::Memzero(Params, ParamsBufferSize);
Call_ProcessParams(Isolate, Context, Info, Params, 0);
OnCall(Params);
Call_ProcessReturnAndOutParams(Isolate, Context, Info, Params, 0);
}
void FFunctionTranslator::CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, void* Params)
{
v8::Local<v8::Value>* Args =
static_cast<v8::Local<v8::Value>*>(FMemory_Alloca(sizeof(v8::Local<v8::Value>) * Arguments.size()));
FMemory::Memset(Args, 0, sizeof(v8::Local<v8::Value>) * Arguments.size());
for (int i = 0; i < Arguments.size(); ++i)
{
Args[i] = Arguments[i]->UEToJsInContainer(Isolate, Context, Params, false);
}
v8::MaybeLocal<v8::Value> Result;
if (UNLIKELY(SkipWorldContextInArg0))
{
Result = JsFunction->Call(Context, This, Arguments.size() - 1, &Args[0] + 1);
}
else
{
Result = JsFunction->Call(Context, This, Arguments.size(), Args);
}
if (!Result.IsEmpty()) // empty mean exception
{
if (Return)
{
Return->JsToUEInContainer(Isolate, Context, Result.ToLocalChecked(), Params, true);
}
for (int i = 0; i < Arguments.size(); ++i)
{
Arguments[i]->JsToUEOutInContainer(Isolate, Context, Args[i], Params, true);
}
}
}
static FOutParmRec* GetMatchOutParmRec(FOutParmRec* OutParam, PropertyMacro* OutProperty)
{
FOutParmRec* Out = OutParam;
while (Out)
{
if (Out->Property == OutProperty)
{
return Out;
}
Out = Out->NextOutParm;
}
return nullptr;
}
void FFunctionTranslator::CallJs(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, v8::Local<v8::Function> JsFunction,
v8::Local<v8::Value> This, UObject* ContextObject, FFrame& Stack, void* RESULT_PARAM)
{
void* Params = Stack.Locals;
FOutParmRec* NewOutParms = nullptr;
const bool CallByBP = Stack.Node != Stack.CurrentNativeFunction;
if (CallByBP)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
{
FMemory::Memzero(Params, ParamsBufferSize);
FOutParmRec** LastOut = &NewOutParms;
// ScriptCore.cpp
for (PropertyMacro* Property = (PropertyMacro*) (
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
Function->ChildProperties
#else
Function->Children
#endif
);
*Stack.Code != EX_EndFunctionParms; Property = (PropertyMacro*) (Property->Next))
{
checkfSlow(Property, TEXT("NULL Property in Function %s"), *Function->GetPathName());
Property->InitializeValue_InContainer(Params);
if ((Property->PropertyFlags & CPF_ReturnParm) != 0)
{
continue;
}
Stack.MostRecentPropertyAddress = nullptr;
if (Property->PropertyFlags & CPF_OutParm)
{
Stack.Step(Stack.Object, Property->ContainerPtrToValuePtr<uint8>(Params));
if (LastOut)
{
CA_SUPPRESS(6263)
FOutParmRec* Out = (FOutParmRec*) FMemory_Alloca(sizeof(FOutParmRec));
ensure(Stack.MostRecentPropertyAddress);
Out->PropAddr = (Stack.MostRecentPropertyAddress != NULL) ? Stack.MostRecentPropertyAddress
: Property->ContainerPtrToValuePtr<uint8>(Params);
Out->Property = Property;
if (*LastOut)
{
(*LastOut)->NextOutParm = Out;
LastOut = &(*LastOut)->NextOutParm;
}
else
{
*LastOut = Out;
}
}
}
else
{
Stack.Step(Stack.Object, Property->ContainerPtrToValuePtr<uint8>(Params));
}
}
}
if (Stack.Code)
{
check(Stack.PeekCode() == EX_EndFunctionParms);
Stack.SkipCode(1); // skip EX_EndFunctionParms
}
}
v8::Local<v8::Value>* Args =
static_cast<v8::Local<v8::Value>*>(FMemory_Alloca(sizeof(v8::Local<v8::Value>) * Arguments.size()));
FMemory::Memset(Args, 0, sizeof(v8::Local<v8::Value>) * Arguments.size());
for (int i = 0; i < Arguments.size(); ++i)
{
const auto Property = Arguments[i]->Property;
if (!CallByBP && (Property->PropertyFlags & CPF_OutParm) && Stack.OutParms) // may be fast call
{
FOutParmRec* Out = Stack.OutParms;
while (Out->Property != Property)
{
Out = Out->NextOutParm;
checkSlow(Out);
}
Args[i] = Arguments[i]->UEToJs(Isolate, Context, Out->PropAddr, false);
continue;
}
Args[i] = Arguments[i]->UEToJsInContainer(Isolate, Context, Params, false);
}
v8::MaybeLocal<v8::Value> Result;
if (UNLIKELY(SkipWorldContextInArg0))
{
Result = JsFunction->Call(Context, This, Arguments.size() - 1, &Args[0] + 1);
}
else
{
Result = JsFunction->Call(Context, This, Arguments.size(), Args);
}
if (!Result.IsEmpty()) // empty mean exception
{
if (Return)
{
Return->JsToUE(Isolate, Context, Result.ToLocalChecked(), RESULT_PARAM, true);
}
auto OutParms = NewOutParms ? NewOutParms : Stack.OutParms;
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->IsOut())
{
auto OutParmRec = GetMatchOutParmRec(OutParms, Arguments[i]->Property);
if (OutParmRec)
{
Arguments[i]->JsToUEOut(Isolate, Context, Args[i], OutParmRec->PropAddr, true);
}
}
}
}
if (Params && Params != Stack.Locals)
{
// destruct properties on the stack, except for out params since we know we didn't use that memory
for (PropertyMacro* Destruct = Function->DestructorLink; Destruct; Destruct = Destruct->DestructorLinkNext)
{
if (!Destruct->HasAnyPropertyFlags(CPF_OutParm))
{
Destruct->DestroyValue_InContainer(Params);
}
}
}
}
bool FFunctionTranslator::IsValid() const
{
return Function.IsValid();
}
FExtensionMethodTranslator::FExtensionMethodTranslator(UFunction* InFunction) : FFunctionTranslator(InFunction, false)
{
TFieldIterator<PropertyMacro> It(InFunction);
PropertyMacro* Property = *It;
IsUObject = Property->IsA<ObjectPropertyBaseMacro>();
Arguments[0] = FPropertyTranslator::Create(Property, true);
}
v8::Local<v8::FunctionTemplate> FExtensionMethodTranslator::ToFunctionTemplate(v8::Isolate* Isolate)
{
return v8::FunctionTemplate::New(Isolate, CallExtension, v8::External::New(Isolate, this));
}
void FExtensionMethodTranslator::CallExtension(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
v8::Context::Scope ContextScope(Context);
FExtensionMethodTranslator* This =
reinterpret_cast<FExtensionMethodTranslator*>((v8::Local<v8::External>::Cast(Info.Data()))->Value());
This->CallExtension(Isolate, Context, Info);
}
void FExtensionMethodTranslator::CallExtension(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, const v8::FunctionCallbackInfo<v8::Value>& Info)
{
#if defined(USE_GLOBAL_PARAMS_BUFFER)
void* Params = Buffer;
#else
void* Params = ParamsBufferSize > 0 ? FMemory_Alloca(ParamsBufferSize) : nullptr;
#endif
if (Params)
Function->InitializeStruct(Params);
if (!Arguments[0]->JsToUEInContainer(Isolate, Context, Info.Holder(), Params, false))
{
if (Params)
{
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
FV8Utils::ThrowException(Isolate, "access a invalid object");
return;
}
for (int i = 1; i < Arguments.size(); ++i)
{
if (UNLIKELY(ArgumentDefaultValues && Info[i - 1]->IsUndefined()))
{
Arguments[i]->Property->CopyCompleteValue_InContainer(Params, ArgumentDefaultValues);
}
else if (!Arguments[i]->JsToUEInContainer(Isolate, Context, Info[i - 1], Params, false))
{
return;
}
}
if (!BindObject.IsValid())
{
BindObject = Function->GetOuterUClass()->GetDefaultObject();
}
BindObject->UObject::ProcessEvent(Function.Get(), Params);
if (Return)
{
Info.GetReturnValue().Set(Return->UEToJsInContainer(Isolate, Context, Params));
Return->Property->DestroyValue_InContainer(Params);
}
for (int i = 1; i < Arguments.size(); ++i)
{
Arguments[i]->UEOutToJsInContainer(Isolate, Context, Info[i - 1], Params, false);
}
// Function->HasAnyFlags()
if (!IsUObject) // FScriptStruct, so copy back
{
auto StructProperty = Arguments[0]->StructProperty;
StructProperty->CopySingleValue(FV8Utils::GetPointer(Info.Holder()), StructProperty->ContainerPtrToValuePtr<void>(Params));
}
if (Params)
{
for (int i = 0; i < Arguments.size(); ++i)
{
if (Arguments[i]->ParamShallowCopySize == 0)
{
Arguments[i]->Property->DestroyValue_InContainer(Params);
}
}
}
}
}; // namespace PUERTS_NAMESPACE