Init
This commit is contained in:
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
* 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 "JSGeneratedClass.h"
|
||||
#include "Engine/Blueprint.h"
|
||||
#include "JSGeneratedFunction.h"
|
||||
#include "JSWidgetGeneratedClass.h"
|
||||
#include "JSAnimGeneratedClass.h"
|
||||
#include "JSLogger.h"
|
||||
|
||||
#define OLD_METHOD_PREFIX "__puerts_old__"
|
||||
#define MIXIN_METHOD_SUFFIX "__puerts_mixin__"
|
||||
|
||||
UClass* UJSGeneratedClass::Create(const FString& Name, UClass* Parent,
|
||||
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, v8::Isolate* Isolate,
|
||||
v8::Local<v8::Function> Constructor, v8::Local<v8::Object> Prototype)
|
||||
{
|
||||
auto Outer = GetTransientPackage();
|
||||
UClass* Class = nullptr;
|
||||
if (Cast<UWidgetBlueprintGeneratedClass>(Parent))
|
||||
{
|
||||
auto JSGeneratedClass = NewObject<UJSWidgetGeneratedClass>(Outer, *Name, RF_Public);
|
||||
#ifdef THREAD_SAFE
|
||||
JSGeneratedClass->Isolate = Isolate;
|
||||
#endif
|
||||
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
|
||||
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
|
||||
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
|
||||
JSGeneratedClass->ClassConstructor = &UJSWidgetGeneratedClass::StaticConstructor;
|
||||
Class = JSGeneratedClass;
|
||||
}
|
||||
else if (Cast<UAnimBlueprintGeneratedClass>(Parent))
|
||||
{
|
||||
auto JSGeneratedClass = NewObject<UJSAnimGeneratedClass>(Outer, *Name, RF_Public);
|
||||
#ifdef THREAD_SAFE
|
||||
JSGeneratedClass->Isolate = Isolate;
|
||||
#endif
|
||||
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
|
||||
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
|
||||
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
|
||||
JSGeneratedClass->ClassConstructor = &UJSAnimGeneratedClass::StaticConstructor;
|
||||
Class = JSGeneratedClass;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto JSGeneratedClass = NewObject<UJSGeneratedClass>(Outer, *Name, RF_Public);
|
||||
#ifdef THREAD_SAFE
|
||||
JSGeneratedClass->Isolate = Isolate;
|
||||
#endif
|
||||
JSGeneratedClass->DynamicInvoker = DynamicInvoker;
|
||||
JSGeneratedClass->Constructor = v8::UniquePersistent<v8::Function>(Isolate, Constructor);
|
||||
JSGeneratedClass->Prototype = v8::UniquePersistent<v8::Object>(Isolate, Prototype);
|
||||
JSGeneratedClass->ClassConstructor = &UJSGeneratedClass::StaticConstructor;
|
||||
Class = JSGeneratedClass;
|
||||
}
|
||||
|
||||
auto Blueprint = NewObject<UBlueprint>(Outer);
|
||||
Blueprint->GeneratedClass = Class;
|
||||
#if ENGINE_MAJOR_VERSION < 5 || WITH_EDITOR
|
||||
Class->ClassGeneratedBy = Blueprint;
|
||||
#endif
|
||||
|
||||
// Set properties we need to regenerate the class with
|
||||
Class->PropertyLink = Parent->PropertyLink;
|
||||
Class->ClassWithin = Parent->ClassWithin;
|
||||
Class->ClassConfigName = Parent->ClassConfigName;
|
||||
|
||||
Class->SetSuperStruct(Parent);
|
||||
Class->ClassFlags |= (Parent->ClassFlags & (CLASS_Inherit | CLASS_ScriptInherit | CLASS_CompiledFromBlueprint));
|
||||
Class->ClassFlags |= CLASS_CompiledFromBlueprint; // AActor::Tick只有有这标记时,才会调用ReceiveTick
|
||||
Class->ClassCastFlags |= Parent->ClassCastFlags;
|
||||
|
||||
return Class;
|
||||
}
|
||||
|
||||
void UJSGeneratedClass::StaticConstructor(const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
auto Class = ObjectInitializer.GetClass();
|
||||
auto Object = ObjectInitializer.GetObj();
|
||||
Class->GetSuperClass()->ClassConstructor(ObjectInitializer);
|
||||
|
||||
if (auto JSGeneratedClass = Cast<UJSGeneratedClass>(Class))
|
||||
{
|
||||
#ifdef THREAD_SAFE
|
||||
v8::Locker Locker(JSGeneratedClass->Isolate);
|
||||
#endif
|
||||
auto PinedDynamicInvoker = JSGeneratedClass->DynamicInvoker.Pin();
|
||||
if (PinedDynamicInvoker)
|
||||
{
|
||||
PinedDynamicInvoker->JsConstruct(JSGeneratedClass, Object, JSGeneratedClass->Constructor, JSGeneratedClass->Prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UJSGeneratedClass::Override(v8::Isolate* Isolate, UClass* Class, UFunction* Super, v8::Local<v8::Function> JSImpl,
|
||||
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool IsNative)
|
||||
{
|
||||
bool Existed = Super->GetOuter() == Class;
|
||||
FName FunctionName = Super->GetFName();
|
||||
if (Existed)
|
||||
{
|
||||
if (auto MaybeJSFunction = Cast<UJSGeneratedFunction>(Super)) //这种情况只需简单替换下js函数
|
||||
{
|
||||
MaybeJSFunction->DynamicInvoker = DynamicInvoker;
|
||||
MaybeJSFunction->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Super, false);
|
||||
MaybeJSFunction->JsFunction.Reset(Isolate, JSImpl);
|
||||
MaybeJSFunction->SetNativeFunc(&UJSGeneratedFunction::execCallJS);
|
||||
return;
|
||||
}
|
||||
// UE_LOG(LogTemp, Error, TEXT("replace %s of %s"), *Super->GetName(), *Class->GetName());
|
||||
//同一Outer下的同名对象只能有一个...
|
||||
Super->Rename(*FString::Printf(TEXT("%s%s"), TEXT(OLD_METHOD_PREFIX), *Super->GetName()), Class,
|
||||
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
|
||||
Class->AddFunctionToFunctionMap(Super, Super->GetFName());
|
||||
// UE_LOG(LogTemp, Error, TEXT("rename to %s"), *Super->GetName());
|
||||
}
|
||||
|
||||
// UE_LOG(LogTemp, Error, TEXT("new function name %s"), *FunctionName.ToString());
|
||||
UJSGeneratedFunction* Function = Cast<UJSGeneratedFunction>(
|
||||
StaticDuplicateObject(Super, Class, FunctionName, RF_Transient, UJSGeneratedFunction::StaticClass()));
|
||||
|
||||
for (TFieldIterator<UFunction> It(Class, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
|
||||
EFieldIteratorFlags::IncludeInterfaces);
|
||||
It; ++It)
|
||||
{
|
||||
if (*It == Function)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Existed)
|
||||
{
|
||||
// UE_LOG(LogTemp, Error, TEXT("new function %s"), *FunctionName.ToString());
|
||||
Function->SetSuperStruct(Super);
|
||||
}
|
||||
else
|
||||
{
|
||||
// UE_LOG(LogTemp, Error, TEXT("replace function %s"), *FunctionName.ToString());
|
||||
Function->SetSuperStruct(Super->GetSuperStruct());
|
||||
}
|
||||
|
||||
Function->Bind();
|
||||
Function->StaticLink(true);
|
||||
|
||||
if (IsNative)
|
||||
{
|
||||
Function->FunctionFlags |= FUNC_Native; //让UE不走解析
|
||||
}
|
||||
|
||||
Function->SetNativeFunc(&UJSGeneratedFunction::execCallJS);
|
||||
|
||||
Function->JsFunction = v8::UniquePersistent<v8::Function>(Isolate, JSImpl);
|
||||
Function->DynamicInvoker = DynamicInvoker;
|
||||
Function->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Function, false);
|
||||
|
||||
if (Existed)
|
||||
{
|
||||
Function->Next = Super->Next;
|
||||
if (Class->Children == Super) // first one
|
||||
{
|
||||
Class->Children = Function;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto P = Class->Children;
|
||||
while (P && P->Next != Super)
|
||||
P = P->Next;
|
||||
check(P);
|
||||
P->Next = Function;
|
||||
}
|
||||
Class->RemoveFunctionFromFunctionMap(Super);
|
||||
}
|
||||
else
|
||||
{
|
||||
Function->Next = Class->Children;
|
||||
Class->Children = Function;
|
||||
}
|
||||
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
|
||||
}
|
||||
|
||||
UFunction* UJSGeneratedClass::Mixin(v8::Isolate* Isolate, UClass* Class, UFunction* Super,
|
||||
TSharedPtr<PUERTS_NAMESPACE::IDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker, bool TakeJsObjectRef, bool Warning)
|
||||
{
|
||||
bool Existed = Super->GetOuter() == Class;
|
||||
|
||||
if (!Existed)
|
||||
{
|
||||
UFunction* Tmp =
|
||||
Cast<UFunction>(StaticDuplicateObject(Super, Class, Super->GetFName(), RF_AllFlags, UFunction::StaticClass()));
|
||||
Tmp->SetSuperStruct(Super);
|
||||
Tmp->Next = Class->Children;
|
||||
Class->Children = Tmp;
|
||||
Class->AddFunctionToFunctionMap(Tmp, Tmp->GetFName());
|
||||
Tmp->SetFlags(Tmp->GetFlags() | RF_Transient);
|
||||
Super = Tmp;
|
||||
}
|
||||
auto MaybeJSFunction = Cast<UJSGeneratedFunction>(Super);
|
||||
if (!MaybeJSFunction)
|
||||
{
|
||||
MaybeJSFunction = UJSGeneratedFunction::GetJSGeneratedFunctionFromScript(Super);
|
||||
}
|
||||
if (MaybeJSFunction)
|
||||
{
|
||||
if (Warning)
|
||||
{
|
||||
UE_LOG(Puerts, Warning, TEXT("Try to mixin a function[%s:%s] already mixin by anthor vm"), *Class->GetName(),
|
||||
*Super->GetName());
|
||||
}
|
||||
return MaybeJSFunction;
|
||||
}
|
||||
|
||||
const FString FunctionName = *FString::Printf(TEXT("%s%s"), *Super->GetName(), TEXT(MIXIN_METHOD_SUFFIX));
|
||||
|
||||
// "Failed to bind native" warning
|
||||
Class->AddNativeFunction(*FunctionName, &UJSGeneratedFunction::execCallMixin);
|
||||
UJSGeneratedFunction* Function = Cast<UJSGeneratedFunction>(
|
||||
StaticDuplicateObject(Super, Class, *FunctionName, RF_AllFlags, UJSGeneratedFunction::StaticClass()));
|
||||
Function->SetFlags(Function->GetFlags() | RF_Transient);
|
||||
|
||||
for (TFieldIterator<UFunction> It(Class, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
|
||||
EFieldIteratorFlags::IncludeInterfaces);
|
||||
It; ++It)
|
||||
{
|
||||
if (*It == Function)
|
||||
{
|
||||
return Function;
|
||||
}
|
||||
}
|
||||
|
||||
Function->SetSuperStruct(Super->GetSuperStruct());
|
||||
|
||||
Function->DynamicInvoker = DynamicInvoker;
|
||||
Function->FunctionTranslator = std::make_unique<PUERTS_NAMESPACE::FFunctionTranslator>(Super, false);
|
||||
Function->TakeJsObjectRef = TakeJsObjectRef;
|
||||
|
||||
Function->Next = Class->Children;
|
||||
Class->Children = Function;
|
||||
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
|
||||
|
||||
Function->FunctionFlags |= FUNC_Native; //让UE不走解析
|
||||
Function->SetNativeFunc(&UJSGeneratedFunction::execCallMixin);
|
||||
Function->Bind();
|
||||
Function->StaticLink(true);
|
||||
Function->ClearInternalFlags(EInternalObjectFlags::Native);
|
||||
|
||||
if (Class->HasAnyInternalFlags(EInternalObjectFlags::RootSet))
|
||||
{
|
||||
Function->AddToRoot();
|
||||
}
|
||||
|
||||
Function->Original = Super;
|
||||
Function->OriginalFunc = Super->GetNativeFunc();
|
||||
Function->OriginalFunctionFlags = Super->FunctionFlags;
|
||||
Super->FunctionFlags |= FUNC_Native; //让UE不走解析
|
||||
Super->SetNativeFunc(&UJSGeneratedFunction::execCallMixin);
|
||||
Class->AddNativeFunction(*Super->GetName(), &UJSGeneratedFunction::execCallMixin);
|
||||
UJSGeneratedFunction::SetJSGeneratedFunctionToScript(Super, Function);
|
||||
|
||||
return Function;
|
||||
}
|
||||
|
||||
void UJSGeneratedClass::Restore(UClass* Class)
|
||||
{
|
||||
FString OrphanedClassString = FString::Printf(TEXT("ORPHANED_DATA_ONLY_%s"), *Class->GetName());
|
||||
FName OrphanedClassName =
|
||||
MakeUniqueObjectName(GetTransientPackage(), UBlueprintGeneratedClass::StaticClass(), FName(*OrphanedClassString));
|
||||
UClass* OrphanedClass = NewObject<UBlueprintGeneratedClass>(GetTransientPackage(), OrphanedClassName, RF_Public | RF_Transient);
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 0
|
||||
OrphanedClass->CppClassStaticFunctions = Class->CppClassStaticFunctions;
|
||||
#else
|
||||
OrphanedClass->ClassAddReferencedObjects = Class->AddReferencedObjects;
|
||||
#endif
|
||||
OrphanedClass->ClassFlags |= CLASS_CompiledFromBlueprint;
|
||||
#if ENGINE_MAJOR_VERSION < 5 || WITH_EDITOR
|
||||
OrphanedClass->ClassGeneratedBy = Class->ClassGeneratedBy;
|
||||
#endif
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
|
||||
UField** PP = nullptr;
|
||||
UField* ChildrenPtr = Class->Children.Get();
|
||||
PP = &ChildrenPtr;
|
||||
#else
|
||||
auto PP = &Class->Children;
|
||||
#endif
|
||||
while (*PP)
|
||||
{
|
||||
if (auto JGF = Cast<UJSGeneratedFunction>(*PP)) // to delete
|
||||
{
|
||||
if (JGF->Original)
|
||||
{
|
||||
if (JGF->Script.Num() == 0)
|
||||
{
|
||||
JGF->Original->Script.Empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
JGF->Original->Script = JGF->Script;
|
||||
}
|
||||
JGF->Original->SetNativeFunc(JGF->OriginalFunc);
|
||||
Class->AddNativeFunction(*JGF->Original->GetName(), JGF->OriginalFunc);
|
||||
JGF->Original->FunctionFlags = JGF->OriginalFunctionFlags;
|
||||
}
|
||||
JGF->JsFunction.Reset();
|
||||
|
||||
*PP = JGF->Next;
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
|
||||
if (PP == &ChildrenPtr)
|
||||
{
|
||||
Class->Children = ChildrenPtr;
|
||||
}
|
||||
#endif
|
||||
|
||||
Class->RemoveFunctionFromFunctionMap(JGF);
|
||||
if (JGF->IsRooted())
|
||||
{
|
||||
JGF->RemoveFromRoot();
|
||||
}
|
||||
JGF->Rename(nullptr, OrphanedClass, REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
|
||||
FLinkerLoad::InvalidateExport(JGF);
|
||||
}
|
||||
else
|
||||
{
|
||||
PP = &(*PP)->Next;
|
||||
}
|
||||
}
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION > 2
|
||||
PP = &ChildrenPtr;
|
||||
#else
|
||||
PP = &Class->Children;
|
||||
#endif
|
||||
while (*PP)
|
||||
{
|
||||
if (auto Function = Cast<UFunction>(*PP))
|
||||
{
|
||||
if (Function->GetName().StartsWith(TEXT(OLD_METHOD_PREFIX)))
|
||||
{
|
||||
Class->RemoveFunctionFromFunctionMap(Function);
|
||||
Function->Rename(*Function->GetName().Mid(strlen(OLD_METHOD_PREFIX)), Class,
|
||||
REN_DontCreateRedirectors | REN_DoNotDirty | REN_ForceNoResetLoaders);
|
||||
Class->AddFunctionToFunctionMap(Function, Function->GetFName());
|
||||
}
|
||||
}
|
||||
PP = &(*PP)->Next;
|
||||
}
|
||||
Class->ClearFunctionMapsCaches();
|
||||
for (TObjectIterator<UClass> It; It; ++It)
|
||||
{
|
||||
if (Class != *It && It->IsChildOf(Class) && !It->HasAnyClassFlags(CLASS_Abstract) &&
|
||||
!It->GetName().StartsWith(TEXT("REINST_")))
|
||||
{
|
||||
It->ClearFunctionMapsCaches();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UJSGeneratedClass::InitPropertiesFromCustomList(uint8* DataPtr, const uint8* DefaultDataPtr)
|
||||
{
|
||||
if (const FCustomPropertyListNode* CustomPropertyList = GetCustomPropertyListForPostConstruction())
|
||||
{
|
||||
UBlueprintGeneratedClass::InitPropertiesFromCustomList(CustomPropertyList, this, DataPtr, DefaultDataPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void UJSGeneratedClass::Release()
|
||||
{
|
||||
for (TFieldIterator<UFunction> It(this, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated,
|
||||
EFieldIteratorFlags::IncludeInterfaces);
|
||||
It; ++It)
|
||||
{
|
||||
if (auto Function = Cast<UJSGeneratedFunction>(*It))
|
||||
{
|
||||
// UE_LOG(LogTemp, Warning, TEXT("release: %s"), *Function->GetName());
|
||||
Function->JsFunction.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
Constructor.Reset();
|
||||
Prototype.Reset();
|
||||
}
|
||||
Reference in New Issue
Block a user