/* * 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 "StructWrapper.h" #include "V8Utils.h" #include "ObjectMapper.h" #include "PathEscape.h" namespace PUERTS_NAMESPACE { void FStructWrapper::AddExtensionMethods(const std::vector& InExtensionMethods) { ExtensionMethods.insert(ExtensionMethods.end(), InExtensionMethods.begin(), InExtensionMethods.end()); } std::shared_ptr FStructWrapper::GetPropertyTranslator(PropertyMacro* InProperty) { auto Iter = PropertiesMap.Find(InProperty->GetFName()); if (!Iter) { std::shared_ptr PropertyTranslator = FPropertyTranslator::Create(InProperty); if (PropertyTranslator) { PropertiesMap.Add(InProperty->GetFName(), PropertyTranslator); Properties.push_back(PropertyTranslator); } return PropertyTranslator; } FPropertyTranslator::CreateOn(InProperty, Iter->get()); return *Iter; } std::shared_ptr FStructWrapper::GetMethodTranslator(UFunction* InFunction, bool IsExtension) { auto Iter = MethodsMap.Find(InFunction->GetFName()); if (!Iter) { std::shared_ptr FunctionTranslator; if (IsExtension) { FunctionTranslator = std::make_shared(InFunction); } else { FunctionTranslator = std::make_shared(InFunction, false); } MethodsMap.Add(InFunction->GetFName(), FunctionTranslator); return FunctionTranslator; } Iter->get()->Init(InFunction, false); return *Iter; } std::shared_ptr FStructWrapper::GetFunctionTranslator(UFunction* InFunction) { auto Iter = FunctionsMap.Find(InFunction->GetFName()); if (!Iter) { auto FunctionTranslator = std::make_shared(InFunction, false); FunctionsMap.Add(InFunction->GetFName(), FunctionTranslator); return FunctionTranslator; } Iter->get()->Init(InFunction, false); return *Iter; } void FStructWrapper::RefreshMethod(UFunction* InFunction) { if (!InFunction->HasAnyFunctionFlags(FUNC_Static)) { GetMethodTranslator(InFunction, false); } } MSVC_PRAGMA(warning(push)) MSVC_PRAGMA(warning(disable : 4191)) void FStructWrapper::InitTemplateProperties( v8::Isolate* Isolate, UStruct* InStruct, v8::Local Template, bool IsReuseTemplate) { auto ClassDefinition = FindClassByType(Struct.Get()); TSet AddedProperties; if (ClassDefinition) { JSPropertyInfo* PropertyInfo = ClassDefinition->Properties; while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter) { AddedProperties.Add(PropertyInfo->Name); if (!IsReuseTemplate) { v8::PropertyAttribute PropertyAttribute = v8::DontDelete; if (!PropertyInfo->Setter) PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly); auto GetterData = PropertyInfo->GetterData ? static_cast>(v8::External::New(Isolate, PropertyInfo->GetterData)) : v8::Local(); auto SetterData = PropertyInfo->SetterData ? static_cast>(v8::External::New(Isolate, PropertyInfo->SetterData)) : v8::Local(); Template->PrototypeTemplate()->SetAccessorProperty(FV8Utils::InternalString(Isolate, PropertyInfo->Name), PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData) : v8::Local(), PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData) : v8::Local(), PropertyAttribute); } ++PropertyInfo; } if (!IsReuseTemplate) { PropertyInfo = ClassDefinition->Variables; while (PropertyInfo && PropertyInfo->Name && PropertyInfo->Getter) { v8::PropertyAttribute PropertyAttribute = v8::DontDelete; if (!PropertyInfo->Setter) PropertyAttribute = (v8::PropertyAttribute)(PropertyAttribute | v8::ReadOnly); auto GetterData = PropertyInfo->GetterData ? static_cast>(v8::External::New(Isolate, PropertyInfo->GetterData)) : v8::Local(); auto SetterData = PropertyInfo->SetterData ? static_cast>(v8::External::New(Isolate, PropertyInfo->SetterData)) : v8::Local(); Template->SetAccessorProperty(FV8Utils::InternalString(Isolate, PropertyInfo->Name), PropertyInfo->Getter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Getter, GetterData) : v8::Local(), PropertyInfo->Setter ? v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) PropertyInfo->Setter, SetterData) : v8::Local(), PropertyAttribute); ++PropertyInfo; } } } for (TFieldIterator PropertyIt(InStruct, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt) { PropertyMacro* Property = *PropertyIt; if (AddedProperties.Contains(Property->GetFName())) { continue; } auto PropertyTranslator = GetPropertyTranslator(Property); if (PropertyTranslator) { if (!IsReuseTemplate) PropertyTranslator->SetAccessor(Isolate, Template); } else { // UE_LOG(LogTemp, Warning, TEXT("%s:%s not supported"), *Property->GetOwnerStruct()->GetName(), *Property->GetName()); } } } v8::Local FStructWrapper::ToFunctionTemplate(v8::Isolate* Isolate, v8::FunctionCallback Construtor) { auto ClassDefinition = FindClassByType(Struct.Get()); bool IsReuseTemplate = false; #if PUERTS_REUSE_STRUCTWRAPPER_FUNCTIONTEMPLATE IsReuseTemplate = true; if (CachedFunctionTemplate.IsEmpty()) { IsReuseTemplate = false; auto Temp = v8::FunctionTemplate::New(Isolate, Construtor, v8::External::New(Isolate, this)); Temp->InstanceTemplate()->SetInternalFieldCount(4); CachedFunctionTemplate.Reset(Isolate, Temp); } auto Result = CachedFunctionTemplate.Get(Isolate); #else auto Result = v8::FunctionTemplate::New( Isolate, Construtor, v8::External::New(Isolate, this)); // 和class的区别就这里传的函数不一样,后续尽量重用 Result->InstanceTemplate()->SetInternalFieldCount(4); #endif TSet AddedMethods; TSet AddedFunctions; if (ClassDefinition) { ExternalInitialize = (V8InitializeFuncType) ClassDefinition->Initialize; ExternalFinalize = ClassDefinition->Finalize; JSFunctionInfo* FunctionInfo = ClassDefinition->Methods; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { AddedMethods.Add(FunctionInfo->Name); if (!IsReuseTemplate) { #ifndef WITH_QUICKJS auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr; if (FastCallInfo) { Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name), v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback, FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) : v8::Local(), v8::Local(), 0, v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo)); } else #endif { Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name), v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback, FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) : v8::Local())); } } ++FunctionInfo; } FunctionInfo = ClassDefinition->Functions; while (FunctionInfo && FunctionInfo->Name && FunctionInfo->Callback) { AddedFunctions.Add(FunctionInfo->Name); if (!IsReuseTemplate) { #ifndef WITH_QUICKJS auto FastCallInfo = FunctionInfo->ReflectionInfo ? FunctionInfo->ReflectionInfo->FastCallInfo() : nullptr; if (FastCallInfo) { Result->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name), v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback, FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) : v8::Local(), v8::Local(), 0, v8::ConstructorBehavior::kThrow, v8::SideEffectType::kHasSideEffect, FastCallInfo)); } else #endif { Result->Set(FV8Utils::InternalString(Isolate, FunctionInfo->Name), v8::FunctionTemplate::New(Isolate, (v8::FunctionCallback) FunctionInfo->Callback, FunctionInfo->Data ? static_cast>(v8::External::New(Isolate, FunctionInfo->Data)) : v8::Local())); } } ++FunctionInfo; } } InitTemplateProperties(Isolate, Struct.Get(), Result, IsReuseTemplate); if (const auto Class = Cast(Struct.Get())) { for (TFieldIterator FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt) { UFunction* Function = *FuncIt; if ((Function->HasAnyFunctionFlags(FUNC_Static) && AddedFunctions.Contains(Function->GetFName())) || (!Function->HasAnyFunctionFlags(FUNC_Static) && AddedMethods.Contains(Function->GetFName()))) { // UE_LOG(LogTemp, Warning, TEXT("%s added"), *Function->GetName()); continue; } FString FuncName = Function->GetName(); auto Key = FV8Utils::InternalString(Isolate, FuncName); #ifdef PUERTS_WITH_EDITOR_SUFFIX // 这里同时绑定带Suffix和不带Suffix的后缀是为了兼容现有的一些js写的代码(PuertsEditor) v8::Local AdditionalKey{}; if (puerts::IsEditorOnlyUFunction(Function)) { FString SuffixFuncName = FuncName + EditorOnlyPropertySuffix.GetData(); AdditionalKey = FV8Utils::InternalString(Isolate, SuffixFuncName); } #endif // 这里同时绑定带Suffix和不带Suffix的后缀是为了兼容现有的一些js写的代码(PuertsEditor) if (Function->HasAnyFunctionFlags(FUNC_Static)) { auto FunctionTranslator = GetFunctionTranslator(Function); AddedFunctions.Add(Function->GetFName()); if (!IsReuseTemplate) { Result->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate)); #ifdef PUERTS_WITH_EDITOR_SUFFIX if (!AdditionalKey.IsEmpty()) { Result->Set(AdditionalKey, FunctionTranslator->ToFunctionTemplate(Isolate)); } #endif } } else { auto FunctionTranslator = GetMethodTranslator(Function, false); AddedMethods.Add(Function->GetFName()); if (!IsReuseTemplate) { Result->PrototypeTemplate()->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate)); #ifdef PUERTS_WITH_EDITOR_SUFFIX if (!AdditionalKey.IsEmpty()) { Result->PrototypeTemplate()->Set(AdditionalKey, FunctionTranslator->ToFunctionTemplate(Isolate)); } #endif } } } for (const FImplementedInterface& Interface : Class->Interfaces) { if (Interface.Class) { for (TFieldIterator ItfFuncIt(Interface.Class, EFieldIteratorFlags::ExcludeSuper); ItfFuncIt; ++ItfFuncIt) { UFunction* ItfFunction = *ItfFuncIt; if (!ItfFunction->HasAnyFunctionFlags(FUNC_Static) && !AddedMethods.Contains(ItfFunction->GetFName())) { auto ItfFunctionTranslator = GetMethodTranslator(ItfFunction, false); AddedMethods.Add(ItfFunction->GetFName()); if (!IsReuseTemplate) Result->PrototypeTemplate()->Set(FV8Utils::InternalString(Isolate, ItfFunction->GetName()), ItfFunctionTranslator->ToFunctionTemplate(Isolate)); } } } } if (!IsReuseTemplate) { Result->Set(FV8Utils::InternalString(Isolate, "Find"), v8::FunctionTemplate::New(Isolate, Find, v8::External::New(Isolate, this))); Result->Set(FV8Utils::InternalString(Isolate, "Load"), v8::FunctionTemplate::New(Isolate, Load, v8::External::New(Isolate, this))); } } for (auto Iter = ExtensionMethods.begin(); Iter != ExtensionMethods.end(); ++Iter) { UFunction* Function = *Iter; if (AddedMethods.Contains(Function->GetFName())) { continue; } auto FunctionTranslator = GetMethodTranslator(Function, true); AddedMethods.Add(Function->GetFName()); if (!IsReuseTemplate) { auto Key = FV8Utils::InternalString(Isolate, Function->GetName()); Result->PrototypeTemplate()->Set(Key, FunctionTranslator->ToFunctionTemplate(Isolate)); } } if (!IsReuseTemplate) Result->Set(FV8Utils::InternalString(Isolate, "StaticClass"), v8::FunctionTemplate::New(Isolate, StaticClass, v8::External::New(Isolate, this))); if (!Struct->IsA() && !IsReuseTemplate) { Result->Set(FV8Utils::InternalString(Isolate, "StaticStruct"), v8::FunctionTemplate::New(Isolate, StaticClass, v8::External::New(Isolate, this))); } #ifndef WITH_QUICKJS if (!IsReuseTemplate) Result->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration( [](v8::Local Property, const v8::PropertyCallbackInfo& Info) { if (Property->IsSymbol()) return; auto InnerIsolate = Info.GetIsolate(); auto Context = InnerIsolate->GetCurrentContext(); auto This = Info.This(); FName RequiredFName(*FV8Utils::ToFString(Info.GetIsolate(), Property)); auto FixedPropertyName = FV8Utils::ToV8String(InnerIsolate, RequiredFName); if (This->GetPrototype()->IsObject()) { auto Proto = This->GetPrototype().As(); if (Proto->Has(Context, FixedPropertyName).FromMaybe(false)) { Info.GetReturnValue().Set(This->Get(Context, FixedPropertyName).ToLocalChecked()); auto DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked(); while (!DescriptorVal->IsObject()) { auto Parent = Proto->GetPrototype(); if (!Parent->IsObject()) break; Proto = Parent.As(); DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked(); } if (DescriptorVal->IsObject()) { auto Descriptor = DescriptorVal.As(); auto Getter = Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "get")).ToLocalChecked(); if (!Getter->IsFunction()) { auto Value = Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "value")).ToLocalChecked(); (void) (Proto->Set(Context, Property, Value)); } else { Proto->SetAccessorProperty(Property, Getter.As(), Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "set")) .ToLocalChecked() .As()); } } } } }, [](v8::Local Property, v8::Local Value, const v8::PropertyCallbackInfo& Info) { if (Property->IsSymbol()) return; auto InnerIsolate = Info.GetIsolate(); auto Context = InnerIsolate->GetCurrentContext(); auto This = Info.This(); FName RequiredFName(*FV8Utils::ToFString(Info.GetIsolate(), Property)); auto FixedPropertyName = FV8Utils::ToV8String(InnerIsolate, RequiredFName); if (This->GetPrototype()->IsObject()) { auto Proto = This->GetPrototype().As(); if (Proto->Has(Context, FixedPropertyName).FromMaybe(false)) { auto _UnUsed = This->Set(Context, FixedPropertyName, Value); Info.GetReturnValue().Set(Value); auto DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked(); while (!DescriptorVal->IsObject()) { auto Parent = Proto->GetPrototype(); if (!Parent->IsObject()) break; Proto = Parent.As(); DescriptorVal = Proto->GetOwnPropertyDescriptor(Context, FixedPropertyName).ToLocalChecked(); } if (DescriptorVal->IsObject()) { auto Descriptor = DescriptorVal.As(); // set first, mush set accessor of object Proto->SetAccessorProperty(Property, Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "get")) .ToLocalChecked() .As(), Descriptor->Get(Context, FV8Utils::ToV8String(InnerIsolate, "set")) .ToLocalChecked() .As()); } } } }, nullptr, nullptr, nullptr, v8::Local(), v8::PropertyHandlerFlags::kNonMasking)); #endif return Result; } MSVC_PRAGMA(warning(pop)) void FStructWrapper::StaticClass(const v8::FunctionCallbackInfo& Info) { v8::Isolate* Isolate = Info.GetIsolate(); v8::Isolate::Scope IsolateScope(Isolate); v8::HandleScope HandleScope(Isolate); v8::Local Context = Isolate->GetCurrentContext(); v8::Context::Scope ContextScope(Context); FStructWrapper* This = reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); if (!This->Struct.IsValid()) { FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC"); return; } auto Result = FV8Utils::IsolateData(Isolate)->FindOrAdd(Isolate, Context, This->Struct->GetClass(), This->Struct.Get()); Info.GetReturnValue().Set(Result); } void FStructWrapper::Find(const v8::FunctionCallbackInfo& Info) { v8::Isolate* Isolate = Info.GetIsolate(); v8::Isolate::Scope IsolateScope(Isolate); v8::HandleScope HandleScope(Isolate); v8::Local Context = Isolate->GetCurrentContext(); v8::Context::Scope ContextScope(Context); FStructWrapper* This = reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); if (!This->Struct.IsValid()) { FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC"); return; } UClass* Class = Cast(This->Struct); if (Class && Info.Length() >= 1 && Info[0]->IsString()) { UObject* Object = nullptr; if (Info.Length() > 1) { UObject* Outer = FV8Utils::GetUObject(Context, Info[1]); Object = StaticFindObject(Class, Outer, *FV8Utils::ToFString(Isolate, Info[0]), false); } else { #if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5 Object = StaticFindFirstObject(Class, *FV8Utils::ToFString(Isolate, Info[0])); #else Object = StaticFindObject(Class, ANY_PACKAGE, *FV8Utils::ToFString(Isolate, Info[0]), false); #endif } if (Object) { auto Result = FV8Utils::IsolateData(Isolate)->FindOrAdd(Isolate, Context, Object->GetClass(), Object); Info.GetReturnValue().Set(Result); } else { Info.GetReturnValue().Set(v8::Undefined(Isolate)); } } else { FV8Utils::ThrowException(Isolate, "invalid argument"); } } void FStructWrapper::Load(const v8::FunctionCallbackInfo& Info) { v8::Isolate* Isolate = Info.GetIsolate(); v8::Isolate::Scope IsolateScope(Isolate); v8::HandleScope HandleScope(Isolate); v8::Local Context = Isolate->GetCurrentContext(); v8::Context::Scope ContextScope(Context); FStructWrapper* This = reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); if (!This->Struct.IsValid()) { FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC"); return; } UClass* Class = Cast(This->Struct); if (Class && Info.Length() > 0 && Info[0]->IsString()) { bool UnEscape = false; if (Info.Length() > 1) { UnEscape = Info[1]->BooleanValue(Isolate); } auto Path = FV8Utils::ToFString(Isolate, Info[0]); auto Object = StaticLoadObject(Class, nullptr, UnEscape ? *TypeScriptVariableNameToFilename(Path) : *Path, nullptr, LOAD_NoWarn); if (Object) { auto Result = FV8Utils::IsolateData(Isolate)->FindOrAdd(Isolate, Context, Object->GetClass(), Object); Info.GetReturnValue().Set(Result); } else { Info.GetReturnValue().Set(v8::Undefined(Isolate)); } } else { FV8Utils::ThrowException(Isolate, "invalid argument"); } } void FScriptStructWrapper::New(const v8::FunctionCallbackInfo& Info) { v8::Isolate* Isolate = Info.GetIsolate(); v8::Isolate::Scope IsolateScope(Isolate); v8::HandleScope HandleScope(Isolate); v8::Local Context = Isolate->GetCurrentContext(); v8::Context::Scope ContextScope(Context); FScriptStructWrapper* This = reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); if (!This->Struct.IsValid()) { FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC"); return; } This->New(Isolate, Context, Info); } void FScriptStructWrapper::New( v8::Isolate* Isolate, v8::Local& Context, const v8::FunctionCallbackInfo& Info) { if (Info.IsConstructCall()) { auto Self = Info.This(); void* Memory = nullptr; { if (ExternalInitialize) { Memory = ExternalInitialize(Info); if (!Memory) // do not bind nullptr { return; } } else { Memory = Alloc(static_cast(Struct.Get())); const int Count = Info.Length() < Properties.size() ? Info.Length() : Properties.size(); for (int i = 0; i < Count; ++i) { Properties[i]->JsToUEInContainer(Isolate, Context, Info[i], Memory, false); } } } FV8Utils::IsolateData(Isolate)->BindStruct(this, Memory, Self, false); } else { FV8Utils::ThrowException(Isolate, "only call as Construct is supported!"); } } void* FScriptStructWrapper::Alloc(UScriptStruct* InScriptStruct) { void* ScriptStructMemory = new char[InScriptStruct->GetStructureSize()]; InScriptStruct->InitializeStruct(ScriptStructMemory); return ScriptStructMemory; } void FScriptStructWrapper::Free(TWeakObjectPtr InStruct, pesapi_finalize InExternalFinalize, void* Ptr) { if (InExternalFinalize) { InExternalFinalize(Ptr, nullptr, nullptr); } else { if (InStruct.IsValid()) InStruct->DestroyStruct(Ptr); delete[] static_cast(Ptr); } } void FScriptStructWrapper::OnGarbageCollectedWithFree(const v8::WeakCallbackInfo& Data) { FScriptStructWrapper* ScriptStructWrapper = Data.GetParameter(); void* ScriptStructMemory = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)); FV8Utils::IsolateData(Data.GetIsolate())->UnBindStruct(ScriptStructWrapper, ScriptStructMemory); Free(ScriptStructWrapper->Struct, ScriptStructWrapper->ExternalFinalize, ScriptStructMemory); } void FScriptStructWrapper::OnGarbageCollected(const v8::WeakCallbackInfo& Data) { void* ScriptStructMemory = DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)); FV8Utils::IsolateData(Data.GetIsolate())->UnBindStruct(Data.GetParameter(), ScriptStructMemory); } void FClassWrapper::OnGarbageCollected(const v8::WeakCallbackInfo& Data) { FV8Utils::IsolateData(Data.GetIsolate()) ->UnBind(Data.GetParameter(), reinterpret_cast(DataTransfer::MakeAddressWithHighPartOfTwo( Data.GetInternalField(0), Data.GetInternalField(1)))); } void FClassWrapper::New(const v8::FunctionCallbackInfo& Info) { v8::Isolate* Isolate = Info.GetIsolate(); v8::Isolate::Scope IsolateScope(Isolate); v8::HandleScope HandleScope(Isolate); v8::Local Context = Isolate->GetCurrentContext(); v8::Context::Scope ContextScope(Context); FClassWrapper* This = reinterpret_cast((v8::Local::Cast(Info.Data()))->Value()); if (!This->Struct.IsValid()) { FV8Utils::ThrowException(Isolate, "Associated UStruct had been GC"); return; } This->New(Isolate, Context, Info); } void FClassWrapper::New(v8::Isolate* Isolate, v8::Local& Context, const v8::FunctionCallbackInfo& Info) { if (Info.IsConstructCall()) { auto Self = Info.This(); UObject* Object = nullptr; auto Class = static_cast(Struct.Get()); { UObject* Outer = GetTransientPackage(); FName Name = NAME_None; EObjectFlags ObjectFlags = RF_NoFlags; if (Info.Length() > 0) { Outer = FV8Utils::GetUObject(Context, Info[0]); if (FV8Utils::IsReleasedPtr(Outer)) { FV8Utils::ThrowException(Isolate, "passing a invalid object"); return; } } if (Info.Length() > 1) { Name = FName(*FV8Utils::ToFString(Isolate, Info[1])); } if (Info.Length() > 2) { ObjectFlags = (EObjectFlags) (Info[2]->Int32Value(Context).ToChecked()); } Object = NewObject(Outer, Class, Name, ObjectFlags); } FV8Utils::IsolateData(Isolate)->Bind(this, Object, Self); } else { FV8Utils::ThrowException(Isolate, "only call as Construct is supported!"); } } } // namespace PUERTS_NAMESPACE