“初始化俯视角工程,带puerts,未编过”

This commit is contained in:
2024-12-01 02:11:25 +08:00
parent 04698dd585
commit 850d76173c
1491 changed files with 271579 additions and 0 deletions
@@ -0,0 +1,36 @@
/*
* 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.
*/
#pragma once
#include "CoreMinimal.h"
#include "ArrayBuffer.generated.h"
USTRUCT(BlueprintType)
struct FArrayBuffer
{
public:
GENERATED_USTRUCT_BODY()
public:
void* Data;
size_t Length;
bool bCopy = false;
};
USTRUCT(BlueprintType)
struct FArrayBufferValue
{
public:
GENERATED_USTRUCT_BODY()
public:
TArray<uint8> Data;
};
@@ -0,0 +1,14 @@
/*
* 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.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#include "StaticCall.hpp"
#include "ScriptBackend.hpp"
#include "Object.hpp"
@@ -0,0 +1,370 @@
/*
* 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.
*/
#pragma once
#if USING_IN_UNREAL_ENGINE
#include "CoreMinimal.h"
#include "UObject/Package.h"
#include "UObject/Class.h"
#else
#include "JSClassRegister.h"
#endif
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if !defined(MAPPER_ISOLATE_DATA_POS)
#define MAPPER_ISOLATE_DATA_POS 0
#endif
#ifndef PESAPI_PRIVATE_DATA_POS_IN_ISOLATE
#define PESAPI_PRIVATE_DATA_POS_IN_ISOLATE (MAPPER_ISOLATE_DATA_POS + 1)
#endif
#define RELEASED_UOBJECT ((UObject*) 12)
#define RELEASED_UOBJECT_MEMBER ((void*) 12)
namespace PUERTS_NAMESPACE
{
template <typename T, typename FT, typename = void>
struct TOuterLinker
{
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
}
};
V8_INLINE void LinkOuterImpl(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
#ifdef WITH_OUTER_LINK
Inner.As<v8::Object>()->Set(Context, 0, Outer);
#endif
}
#if USING_IN_UNREAL_ENGINE
FORCEINLINE UScriptStruct* GetScriptStructInCoreUObject(const TCHAR* Name)
{
static UPackage* CoreUObjectPkg = FindObjectChecked<UPackage>(nullptr, TEXT("/Script/CoreUObject"));
return FindObjectChecked<UScriptStruct>(CoreUObjectPkg, Name);
}
template <class T, typename Enable = void>
struct TScriptStructTraits
{
};
template <>
struct TScriptStructTraits<FVector>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector>::Get();
}
};
template <>
struct TScriptStructTraits<FVector2D>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector2D>::Get();
}
};
template <>
struct TScriptStructTraits<FVector4>
{
static UScriptStruct* Get()
{
return TBaseStructure<FVector4>::Get();
}
};
template <>
struct TScriptStructTraits<FRotator>
{
static UScriptStruct* Get()
{
return TBaseStructure<FRotator>::Get();
}
};
template <>
struct TScriptStructTraits<FQuat>
{
static UScriptStruct* Get()
{
return TBaseStructure<FQuat>::Get();
}
};
template <>
struct TScriptStructTraits<FTransform>
{
static UScriptStruct* Get()
{
return TBaseStructure<FTransform>::Get();
}
};
template <>
struct TScriptStructTraits<FLinearColor>
{
static UScriptStruct* Get()
{
return TBaseStructure<FLinearColor>::Get();
}
};
template <>
struct TScriptStructTraits<FColor>
{
static UScriptStruct* Get()
{
return TBaseStructure<FColor>::Get();
}
};
template <>
struct TScriptStructTraits<FGuid>
{
static UScriptStruct* Get()
{
return TBaseStructure<FGuid>::Get();
}
};
template <>
struct TScriptStructTraits<FBox2D>
{
static UScriptStruct* Get()
{
return TBaseStructure<FBox2D>::Get();
}
};
template <>
struct TScriptStructTraits<FIntPoint>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("IntPoint"));
}
};
template <>
struct TScriptStructTraits<FIntVector>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("IntVector"));
}
};
template <>
struct TScriptStructTraits<FPlane>
{
static UScriptStruct* Get()
{
return GetScriptStructInCoreUObject(TEXT("Plane"));
}
};
template <class...>
using ToVoid = void;
template <typename T, typename = void>
struct HasStaticStructHelper : std::false_type
{
};
template <typename T>
struct HasStaticStructHelper<T, ToVoid<decltype(&T::StaticStruct)>> : std::true_type
{
};
template <typename T>
struct TScriptStructTraits<T, typename std::enable_if<HasStaticStructHelper<T>::value>::type>
{
static UScriptStruct* Get()
{
return T::StaticStruct();
}
};
template <typename T, typename FT>
struct TOuterLinker<T, FT, ToVoid<decltype(&TScriptStructTraits<FT>::Get)>>
{
V8_INLINE static void Link(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
LinkOuterImpl(Context, Outer, Inner);
}
};
#endif
class JSENV_API DataTransfer
{
public:
FORCEINLINE static void* MakeAddressWithHighPartOfTwo(void* Address1, void* Address2)
{
UPTRINT High = reinterpret_cast<UPTRINT>(Address1) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
UPTRINT Low = (reinterpret_cast<UPTRINT>(Address2) >> (sizeof(UPTRINT) / 2)) &
~(((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //右移,然后清除高位
return reinterpret_cast<void*>(High | Low);
}
FORCEINLINE static void SplitAddressToHighPartOfTwo(const void* Address, UPTRINT& High, UPTRINT& Low)
{
High = reinterpret_cast<UPTRINT>(Address) & (((UPTRINT) -1) << (sizeof(UPTRINT) / 2)); //清除低位
Low = reinterpret_cast<UPTRINT>(Address) << (sizeof(UPTRINT) / 2);
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index)
{
int P1 = Index << 1;
int P2 = P1 + 1;
if (V8_LIKELY(Object->InternalFieldCount() > P2))
{
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
Object->GetAlignedPointerFromInternalField(P1), Object->GetAlignedPointerFromInternalField(P2)));
}
return nullptr;
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object)
{
if (V8_LIKELY(Object->InternalFieldCount() > 1))
{
return static_cast<T*>(MakeAddressWithHighPartOfTwo(
Object->GetAlignedPointerFromInternalField(0), Object->GetAlignedPointerFromInternalField(1)));
}
return nullptr;
}
//替代 Object->SetAlignedPointerInInternalField(Index, Ptr);
FORCEINLINE static void SetPointer(v8::Isolate* Isolate, v8::Local<v8::Object> Object, const void* Ptr, int Index)
{
// Object->SetInternalField(Index, v8::External::New(Isolate, Ptr));
// Object->SetAlignedPointerInInternalField(Index, Ptr);
UPTRINT High;
UPTRINT Low;
SplitAddressToHighPartOfTwo(Ptr, High, Low);
Object->SetAlignedPointerInInternalField(Index * 2, reinterpret_cast<void*>(High));
Object->SetAlignedPointerInInternalField(Index * 2 + 1, reinterpret_cast<void*>(Low));
}
template <typename T>
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
{
return static_cast<T*>(Isolate->GetData(MAPPER_ISOLATE_DATA_POS));
}
FORCEINLINE static void* GetIsolatePrivateData(v8::Isolate* Isolate)
{
return Isolate->GetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE);
}
FORCEINLINE static void SetIsolatePrivateData(v8::Isolate* Isolate, void* PrivateData)
{
Isolate->SetData(PESAPI_PRIVATE_DATA_POS_IN_ISOLATE, PrivateData);
}
static v8::Local<v8::Value> FindOrAddCData(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, const void* TypeId, const void* Ptr, bool PassByPointer);
static bool IsInstanceOf(v8::Isolate* Isolate, const void* TypeId, v8::Local<v8::Object> JsObject);
static v8::Local<v8::Value> UnRef(v8::Isolate* Isolate, const v8::Local<v8::Value>& Value);
static void UpdateRef(v8::Isolate* Isolate, v8::Local<v8::Value> Outer, const v8::Local<v8::Value>& Value);
static std::weak_ptr<int> GetJsEnvLifeCycleTracker(v8::Isolate* Isolate);
#if USING_IN_UNREAL_ENGINE
template <typename T>
static v8::Local<v8::Value> FindOrAddObject(v8::Isolate* Isolate, v8::Local<v8::Context>& Context, T* UEObject)
{
return FindOrAddObject(Isolate, Context, UEObject == nullptr ? T::StaticClass() : UEObject->GetClass(), UEObject);
}
static v8::Local<v8::Value> FindOrAddObject(
v8::Isolate* Isolate, v8::Local<v8::Context>& Context, UClass* Class, UObject* UEObject);
template <typename T>
static v8::Local<v8::Value> FindOrAddStruct(v8::Isolate* Isolate, v8::Local<v8::Context> Context, void* Ptr, bool PassByPointer)
{
return FindOrAddStruct(Isolate, Context, TScriptStructTraits<T>::Get(), Ptr, PassByPointer);
}
static v8::Local<v8::Value> FindOrAddStruct(
v8::Isolate* Isolate, v8::Local<v8::Context> Context, UScriptStruct* ScriptStruct, void* Ptr, bool PassByPointer);
template <typename T>
static bool IsInstanceOf(v8::Isolate* Isolate, v8::Local<v8::Object> JsObject)
{
return IsInstanceOf(Isolate, TScriptStructTraits<T>::Get(), JsObject);
}
static bool IsInstanceOf(v8::Isolate* Isolate, UStruct* Struct, v8::Local<v8::Object> JsObject);
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
static void ThrowException(v8::Isolate* Isolate, const char* Message);
#endif
template <typename T1, typename T2>
FORCEINLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
TOuterLinker<T1, T2>::Link(Context, Outer, Inner);
}
FORCEINLINE static v8::Local<v8::ArrayBuffer> NewArrayBuffer(v8::Local<v8::Context> Context, void* Data, size_t DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_New_Without_Stl(Context->GetIsolate(), Data, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
return v8::ArrayBuffer::New(Context->GetIsolate(), Data, DataLength);
#else
auto Backing = v8::ArrayBuffer::NewBackingStore(Data, DataLength, v8::BackingStore::EmptyDeleter, nullptr);
return v8::ArrayBuffer::New(Context->GetIsolate(), std::move(Backing));
#endif
#endif
}
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer)
{
size_t DataLength;
return GetArrayBufferData(InArrayBuffer, DataLength);
}
FORCEINLINE static void* GetArrayBufferData(v8::Local<v8::ArrayBuffer> InArrayBuffer, size_t& DataLength)
{
#if defined(HAS_ARRAYBUFFER_NEW_WITHOUT_STL)
return v8::ArrayBuffer_Get_Data(InArrayBuffer, DataLength);
#else
#if USING_IN_UNREAL_ENGINE
DataLength = InArrayBuffer->GetContents().ByteLength();
return InArrayBuffer->GetContents().Data();
#else
auto BS = InArrayBuffer->GetBackingStore();
DataLength = BS->ByteLength();
return BS->Data();
#endif
#endif
}
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#include "NamespaceDef.h"
#include "CoreUObject.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
class UDynamicDelegateProxy;
class UJSGeneratedFunction;
namespace PUERTS_NAMESPACE
{
class IDynamicInvoker
{
public:
virtual void InvokeDelegateCallback(UDynamicDelegateProxy* Proxy, void* Params) = 0;
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void JsConstruct(UClass* Class, UObject* Object, const v8::UniquePersistent<v8::Function>& Constructor,
const v8::UniquePersistent<v8::Object>& Prototype) = 0;
virtual void InvokeJsMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
virtual void InvokeMixinMethod(UObject* ContextObject, UJSGeneratedFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
#endif
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,22 @@
/*
* 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.
*/
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "ExtensionMethods.generated.h"
/**
*
*/
UCLASS()
class JSENV_API UExtensionMethods : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
};
@@ -0,0 +1,16 @@
/*
* 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.
*/
#pragma once
#include "inttypes.h"
#include "CoreMinimal.h"
typedef void (*FuncPtr)();
JSENV_API void SetFunctionArray(FuncPtr* FuncArray, uint32_t FuncArrayLength);
@@ -0,0 +1,175 @@
/*
* 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.
*/
#pragma once
#include "functional"
#if USING_IN_UNREAL_ENGINE
#include "CoreMinimal.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#else
#define JSENV_API
#define FORCEINLINE V8_INLINE
#define UPTRINT uintptr_t
#endif
#include <string>
#include "PuertsNamespaceDef.h"
#include "pesapi.h"
#include "TypeInfo.hpp"
#if USING_IN_UNREAL_ENGINE
static const FAnsiStringView EditorOnlyPropertySuffix = "_EditorOnly";
#endif
namespace PUERTS_NAMESPACE
{
class CFunctionInfo;
MSVC_PRAGMA(warning(push))
MSVC_PRAGMA(warning(disable : 4191))
struct JSENV_API JSFunctionInfo
{
JSFunctionInfo() : Name(nullptr), Callback(nullptr)
{
}
JSFunctionInfo(
const char* InName, pesapi_callback InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr)
: Name(InName), Callback(InCallback), Data(InData), ReflectionInfo(InReflectionInfo)
{
}
template <class CallbackType>
JSFunctionInfo(
const char* InName, CallbackType InCallback, void* InData = nullptr, const CFunctionInfo* InReflectionInfo = nullptr)
: Name(InName), Callback(reinterpret_cast<pesapi_callback>(InCallback)), Data(InData), ReflectionInfo(InReflectionInfo)
{
}
const char* Name;
pesapi_callback Callback;
void* Data = nullptr;
const CFunctionInfo* ReflectionInfo = nullptr;
};
struct JSENV_API JSPropertyInfo
{
JSPropertyInfo() : Name(nullptr), Getter(nullptr), Setter(nullptr)
{
}
JSPropertyInfo(const char* InName, pesapi_callback InGetter, pesapi_callback InSetter, void* InGetterData = nullptr,
void* InSetterData = nullptr)
: Name(InName), Getter(InGetter), Setter(InSetter), GetterData(InGetterData), SetterData(InSetterData)
{
}
template <class CallbackType>
JSPropertyInfo(const char* InName, CallbackType InGetter, CallbackType InSetter, void* InGetterData = nullptr,
void* InSetterData = nullptr)
: Name(InName)
, Getter(reinterpret_cast<pesapi_callback>(InGetter))
, Setter(reinterpret_cast<pesapi_callback>(InSetter))
, GetterData(InGetterData)
, SetterData(InSetterData)
{
}
const char* Name;
pesapi_callback Getter;
pesapi_callback Setter;
void* GetterData = nullptr;
void* SetterData = nullptr;
};
struct NamedFunctionInfo;
struct NamedPropertyInfo;
struct JSENV_API JSClassDefinition
{
const void* TypeId;
const void* SuperTypeId;
const char* ScriptName;
const char* UETypeName;
pesapi_constructor Initialize;
template <class InitializeType>
void SetInitialize(InitializeType InInitialize)
{
Initialize = reinterpret_cast<pesapi_constructor>(InInitialize);
}
JSFunctionInfo* Methods; //成员方法
JSFunctionInfo* Functions; //静态方法
JSPropertyInfo* Properties; //成员属性
JSPropertyInfo* Variables; //静态属性
pesapi_finalize Finalize;
// int InternalFieldCount;
NamedFunctionInfo* ConstructorInfos;
NamedFunctionInfo* MethodInfos;
NamedFunctionInfo* FunctionInfos;
NamedPropertyInfo* PropertyInfos;
NamedPropertyInfo* VariableInfos;
void* Data = nullptr;
pesapi_on_native_object_enter OnEnter = nullptr;
pesapi_on_native_object_exit OnExit = nullptr;
};
MSVC_PRAGMA(warning(pop))
#define JSClassEmptyDefinition \
{ \
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \
}
void JSENV_API RegisterJSClass(const JSClassDefinition& ClassDefinition);
void JSENV_API SetClassTypeInfo(const void* TypeId, const NamedFunctionInfo* ConstructorInfos, const NamedFunctionInfo* MethodInfos,
const NamedFunctionInfo* FunctionInfos, const NamedPropertyInfo* PropertyInfos, const NamedPropertyInfo* VariableInfos);
void JSENV_API ForeachRegisterClass(std::function<void(const JSClassDefinition* ClassDefinition)>);
JSENV_API const JSClassDefinition* FindClassByID(const void* TypeId);
JSENV_API void OnClassNotFound(pesapi_class_not_found_callback Callback);
JSENV_API const JSClassDefinition* LoadClassByID(const void* TypeId);
JSENV_API const JSClassDefinition* FindCppTypeClassByName(const std::string& Name);
JSENV_API bool TraceObjectLifecycle(const void* TypeId, pesapi_on_native_object_enter OnEnter, pesapi_on_native_object_exit OnExit);
#if USING_IN_UNREAL_ENGINE
typedef void (*AddonRegisterFunc)(v8::Local<v8::Context> Context, v8::Local<v8::Object> Exports);
AddonRegisterFunc FindAddonRegisterFunc(const std::string& Name);
void RegisterAddon(const char* Name, AddonRegisterFunc RegisterFunc);
JSENV_API const JSClassDefinition* FindClassByType(UStruct* Type);
JSENV_API bool IsEditorOnlyUFunction(const UFunction* Func);
#endif
} // namespace PUERTS_NAMESPACE
#define PUERTS_MODULE(Name, RegFunc) \
static struct FAutoRegisterFor##Name \
{ \
FAutoRegisterFor##Name() \
{ \
PUERTS_NAMESPACE::RegisterAddon(#Name, (RegFunc)); \
} \
} _AutoRegisterFor##Name
@@ -0,0 +1,39 @@
/*
* 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.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#include "CoreMinimal.h"
JSENV_API DECLARE_LOG_CATEGORY_EXTERN(Puerts, Log, All);
namespace PUERTS_NAMESPACE
{
class JSENV_API ILogger
{
public:
virtual void Log(const FString& Message) const = 0;
virtual void Info(const FString& Message) const = 0;
virtual void Warn(const FString& Message) const = 0;
virtual void Error(const FString& Message) const = 0;
};
class JSENV_API FDefaultLogger : public ILogger
{
public:
virtual ~FDefaultLogger()
{
}
void Log(const FString& Message) const override;
void Info(const FString& Message) const override;
void Warn(const FString& Message) const override;
void Error(const FString& Message) const override;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,53 @@
/*
* 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.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#include "CoreMinimal.h"
namespace PUERTS_NAMESPACE
{
class IJSModuleLoader
{
public:
virtual bool Search(const FString& RequiredDir, const FString& RequiredModule, FString& Path, FString& AbsolutePath) = 0;
virtual bool Load(const FString& Path, TArray<uint8>& Content) = 0;
virtual FString& GetScriptRoot() = 0;
virtual ~IJSModuleLoader()
{
}
};
class JSENV_API DefaultJSModuleLoader : public IJSModuleLoader
{
public:
explicit DefaultJSModuleLoader(const FString& InScriptRoot) : ScriptRoot(InScriptRoot)
{
}
virtual bool Search(const FString& RequiredDir, const FString& RequiredModule, FString& Path, FString& AbsolutePath) override;
virtual bool Load(const FString& Path, TArray<uint8>& Content) override;
virtual FString& GetScriptRoot() override;
virtual bool CheckExists(const FString& PathIn, FString& Path, FString& AbsolutePath);
virtual bool SearchModuleInDir(const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath);
virtual bool SearchModuleWithExtInDir(const FString& Dir, const FString& RequiredModule, FString& Path, FString& AbsolutePath);
FString ScriptRoot;
};
} // namespace PUERTS_NAMESPACE
+102
View File
@@ -0,0 +1,102 @@
/*
* 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.
*/
#pragma once
#include <string>
#include <functional>
#include <memory>
#include "CoreMinimal.h"
#include "JSLogger.h"
#include "JSModuleLoader.h"
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "ExtensionMethods.h"
#endif
namespace PUERTS_NAMESPACE
{
class JSENV_API IJsEnv
{
public:
virtual void Start(const FString& ModuleName, const TArray<TPair<FString, UObject*>>& Arguments) = 0;
virtual bool IdleNotificationDeadline(double DeadlineInSeconds) = 0;
virtual void LowMemoryNotification() = 0;
virtual void RequestMinorGarbageCollectionForTesting() = 0;
virtual void RequestFullGarbageCollectionForTesting() = 0;
virtual void WaitDebugger(double Timeout) = 0;
#if !defined(ENGINE_INDEPENDENT_JSENV)
virtual void TryBindJs(const class UObjectBase* InObject) = 0;
virtual void RebindJs() = 0;
#endif
virtual void ReloadModule(FName ModuleName, const FString& JsSource) = 0;
virtual void ReloadSource(const FString& Path, const std::string& JsSource) = 0;
virtual void OnSourceLoaded(std::function<void(const FString&)> Callback) = 0;
virtual FString CurrentStackTrace() = 0;
virtual void InitExtensionMethodsMap() = 0;
virtual ~IJsEnv()
{
}
};
class JSENV_API FJsEnv // : public TSharedFromThis<FJsEnv> // only a wrapper
{
public:
explicit FJsEnv(const FString& ScriptRoot = TEXT("JavaScript"));
FJsEnv(std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InDebugPort,
std::function<void(const FString&)> InOnSourceLoadedCallback = nullptr, const FString InFlags = FString(),
void* InExternalRuntime = nullptr, void* InExternalContext = nullptr);
void Start(const FString& ModuleName, const TArray<TPair<FString, UObject*>>& Arguments = TArray<TPair<FString, UObject*>>());
bool IdleNotificationDeadline(double DeadlineInSeconds);
void LowMemoryNotification();
// equivalent to Isolate->RequestGarbageCollectionForTesting(v8::Isolate::kMinorGarbageCollection)
// It is only valid to call this function if --expose_gc was specified
void RequestMinorGarbageCollectionForTesting();
// equivalent to Isolate->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection)
void RequestFullGarbageCollectionForTesting();
void WaitDebugger(double Timeout = 0);
void TryBindJs(const class UObjectBase* InObject);
void ReloadModule(FName ModuleName, const FString& JsSource);
void ReloadSource(const FString& Path, const std::string& JsSource);
void OnSourceLoaded(std::function<void(const FString&)> Callback);
void RebindJs();
FString CurrentStackTrace();
void InitExtensionMethodsMap();
private:
std::unique_ptr<IJsEnv> GameScript;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,47 @@
/*
* 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.
*/
#pragma once
#include <vector>
#include "CoreMinimal.h"
#include "JsEnv.h"
namespace PUERTS_NAMESPACE
{
class JSENV_API FJsEnvGroup
{
public:
explicit FJsEnvGroup(int Size, const FString& ScriptRoot = TEXT("JavaScript"));
FJsEnvGroup(int Size, std::shared_ptr<IJSModuleLoader> InModuleLoader, std::shared_ptr<ILogger> InLogger, int InDebugStartPort,
std::function<void(const FString&)> InOnSourceLoadedCallback = nullptr, const FString InFlags = FString(),
void* InExternalRuntime = nullptr, void* InExternalContext = nullptr);
~FJsEnvGroup();
void TryBindJs(const class UObjectBase* InObject);
void ReloadModule(FName ModuleName, const FString& JsSource);
void RebindJs();
void InitExtensionMethodsMap();
std::shared_ptr<IJsEnv> Get(int Index);
void SetJsEnvSelector(std::function<int(UObject*, int)> InSelector);
private:
std::vector<std::shared_ptr<IJsEnv>> JsEnvList;
void Init();
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,46 @@
/*
* 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.
*/
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleInterface.h"
#include "Modules/ModuleManager.h"
#if !defined(ENGINE_INDEPENDENT_JSENV)
#include "EngineMinimal.h"
#endif
/**
* The public interface to this module
*/
class IJsEnvModule : public IModuleInterface
{
public:
/**
* Singleton-like access to this module's interface. This is just for convenience!
* Beware of calling this during the shutdown phase, though. Your module might have been unloaded already.
*
* @return Returns singleton instance, loading the module on demand if needed
*/
static inline IJsEnvModule& Get()
{
return FModuleManager::LoadModuleChecked<IJsEnvModule>("JsEnv");
}
/**
* Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true.
*
* @return True if the module is loaded and ready to use
*/
static inline bool IsAvailable()
{
return FModuleManager::Get().IsModuleLoaded("JsEnv");
}
virtual void* GetV8Platform() = 0;
};
@@ -0,0 +1,305 @@
/*
* 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.
*/
#pragma once
#include "NamespaceDef.h"
#include "Binding.hpp"
#include "JSLogger.h"
#include "V8Utils.h"
namespace PUERTS_NAMESPACE
{
class FJsObjectPropertyTranslator;
}
#include "CoreMinimal.h"
#include "JsObject.generated.h"
USTRUCT(BlueprintType)
struct FJsObject
{
public:
GENERATED_USTRUCT_BODY()
FJsObject() : Isolate(nullptr)
{
}
FJsObject(const FJsObject& InOther)
{
if (InOther.JsEnvLifeCycleTracker.expired())
{
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
if (!JsEnvLifeCycleTracker.expired())
{
GObject.Reset();
GContext.Reset();
Isolate = nullptr;
}
return;
}
Isolate = InOther.Isolate;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
}
FJsObject(v8::Local<v8::Context> InContext, v8::Local<v8::Object> InObject)
: Isolate(InContext->GetIsolate()), GContext(InContext->GetIsolate(), InContext), GObject(InContext->GetIsolate(), InObject)
{
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
}
~FJsObject()
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
if (JsEnvLifeCycleTracker.expired())
{
#if V8_MAJOR_VERSION < 11
GObject.Empty();
GContext.Empty();
#endif
}
else
{
GObject.Reset();
GContext.Reset();
}
}
FJsObject& operator=(const FJsObject& InOther)
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
if (InOther.JsEnvLifeCycleTracker.expired())
{
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
if (!JsEnvLifeCycleTracker.expired())
{
GObject.Reset();
GContext.Reset();
Isolate = nullptr;
}
return *this;
}
Isolate = InOther.Isolate;
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
JsEnvLifeCycleTracker = PUERTS_NAMESPACE::DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
return *this;
}
template <typename T>
T Get(const char* Key) const
{
if (JsEnvLifeCycleTracker.expired())
{
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
return {};
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
auto MaybeValue = Object->Get(Context, PUERTS_NAMESPACE::v8_impl::Converter<const char*>::toScript(Context, Key));
v8::Local<v8::Value> Val;
if (MaybeValue.ToLocal(&Val))
{
return PUERTS_NAMESPACE::v8_impl::Converter<T>::toCpp(Context, Val);
}
return {};
}
template <typename T>
void Set(const char* Key, T Val) const
{
if (JsEnvLifeCycleTracker.expired())
{
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
return;
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
auto _UnUsed = Object->Set(Context, PUERTS_NAMESPACE::v8_impl::Converter<const char*>::toScript(Context, Key),
PUERTS_NAMESPACE::v8_impl::Converter<T>::toScript(Context, Val));
}
template <typename... Args>
void Action(Args... cppArgs) const
{
if (JsEnvLifeCycleTracker.expired())
{
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
return;
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
if (!Object->IsFunction())
{
UE_LOG(Puerts, Error, TEXT("call a non-function object!"));
return;
}
v8::TryCatch TryCatch(Isolate);
auto _UnUsed = InvokeHelper(Context, Object, cppArgs...);
if (TryCatch.HasCaught())
{
UE_LOG(
Puerts, Error, TEXT("call function throw: %s"), *PUERTS_NAMESPACE::FV8Utils::TryCatchToString(Isolate, &TryCatch));
}
}
template <typename Ret, typename... Args>
Ret Func(Args... cppArgs) const
{
if (JsEnvLifeCycleTracker.expired())
{
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
return {};
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
if (!Object->IsFunction())
{
UE_LOG(Puerts, Error, TEXT("call a non-function object!"));
return {};
}
v8::TryCatch TryCatch(Isolate);
auto MaybeRet = InvokeHelper(Context, Object, cppArgs...);
if (TryCatch.HasCaught())
{
UE_LOG(
Puerts, Error, TEXT("call function throw: %s"), *PUERTS_NAMESPACE::FV8Utils::TryCatchToString(Isolate, &TryCatch));
}
if (!MaybeRet.IsEmpty())
{
return PUERTS_NAMESPACE::v8_impl::Converter<Ret>::toCpp(Context, MaybeRet.ToLocalChecked());
}
return {};
}
private:
FORCEINLINE v8::Local<v8::Object> GetJsObject() const
{
if (JsEnvLifeCycleTracker.expired())
{
UE_LOG(Puerts, Error, TEXT("JsEnv associated had release!"));
return {};
}
if (!GObject.IsEmpty())
{
return GObject.Get(Isolate);
}
else
{
return {};
}
}
template <typename... Args>
FORCEINLINE auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object, Args... CppArgs) const
{
v8::Local<v8::Value> Argv[sizeof...(Args)]{PUERTS_NAMESPACE::v8_impl::Converter<Args>::toScript(Context, CppArgs)...};
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), sizeof...(Args), Argv);
}
FORCEINLINE auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object) const
{
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), 0, nullptr);
}
private:
v8::Isolate* Isolate;
#if V8_MAJOR_VERSION >= 11
v8::Persistent<v8::Context> GContext;
v8::Persistent<v8::Object> GObject;
#else
v8::Global<v8::Context> GContext;
v8::Global<v8::Object> GObject;
#endif
std::weak_ptr<int> JsEnvLifeCycleTracker;
friend struct PUERTS_NAMESPACE::v8_impl::Converter<FJsObject>;
friend class PUERTS_NAMESPACE::FJsObjectPropertyTranslator;
};
namespace PUERTS_NAMESPACE
{
template <>
struct ScriptTypeName<FJsObject>
{
static constexpr auto value()
{
return internal::Literal("object");
}
};
namespace v8_impl
{
template <>
struct Converter<FJsObject>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FJsObject value)
{
return value.GObject.Get(context->GetIsolate());
}
static FJsObject toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return FJsObject(context, value.As<v8::Object>());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject();
}
};
} // namespace v8_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,15 @@
/*
* 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.
*/
#pragma once
#include "PuertsNamespaceDef.h"
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
namespace v8 = v8_qjs;
#endif
@@ -0,0 +1,92 @@
/*
* 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.
*/
#pragma once
#if defined(BUILDING_PES_EXTENSION)
#include "PesapiObject.hpp"
#endif
#if !defined(BUILDING_PES_EXTENSION) || defined(PES_EXTENSION_WITH_V8_API)
#include "V8Object.hpp"
#endif
namespace PUERTS_NAMESPACE
{
namespace internal
{
constexpr std::size_t NumDigits(std::size_t n)
{
return n < 10 ? 1 : NumDigits(n / 10) + 1;
}
template <char... Chars>
struct CharList
{
const char Str[sizeof...(Chars)] = {Chars...};
};
template <std::size_t D, std::size_t N, char... Chars>
struct SI2A
{
using type = typename SI2A<D - 1, N / 10, '0' + N % 10, Chars...>::type;
};
template <std::size_t N, char... Chars>
struct SI2A<1, N, Chars...>
{
using type = CharList<'0' + N, Chars..., '\0'>;
};
template <std::size_t N>
using SI2A_T = typename SI2A<NumDigits(N), N>::type;
template <size_t N, typename... Rest>
struct ParamsDecl
{
};
template <size_t N, typename T, typename... Rest>
struct ParamsDecl<N, T, Rest...>
{
static constexpr auto Get()
{
return ParamsDecl<N, T>::Get() + Literal(", ") + ParamsDecl<N + 1, Rest...>::Get();
}
};
template <size_t N, typename T>
struct ParamsDecl<N, T>
{
static constexpr auto Get()
{
return Literal("p") + Literal(SI2A_T<N>().Str) + Literal(":") + ScriptTypeNameWithNamespace<T>::value();
}
};
template <size_t N>
struct ParamsDecl<N>
{
static constexpr auto Get()
{
return Literal("");
}
};
} // namespace internal
template <typename R, typename... Args>
struct ScriptTypeName<std::function<R(Args...)>>
{
static constexpr auto value()
{
return internal::Literal("(") + internal::ParamsDecl<0, Args...>::Get() + internal::Literal(") => ") +
ScriptTypeNameWithNamespace<R>::value();
}
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,57 @@
/*
* 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.
*/
#pragma once
#include "CoreMinimal.h"
#include "UObject/GCObject.h"
#include "PuertsNamespaceDef.h"
#ifdef THREAD_SAFE
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
namespace v8_qjs
#else
namespace v8
#endif
{
class Isolate;
}
#endif
namespace PUERTS_NAMESPACE
{
class JSENV_API FObjectRetainer : public FGCObject
{
public:
void Retain(UObject* Object);
void Release(UObject* Object);
void Clear();
virtual void AddReferencedObjects(FReferenceCollector& Collector) override;
virtual ~FObjectRetainer() override;
FORCEINLINE void SetName(FString InName)
{
Name = InName;
}
virtual FString GetReferencerName() const override;
#ifdef THREAD_SAFE
FCriticalSection RetainedObjectsCritical;
#endif
private:
TSet<UObject*> RetainedObjects;
FString Name = TEXT("FObjectRetainer");
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,85 @@
/*
* 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.
*/
#pragma once
#include "PuertsNamespaceDef.h"
namespace PUERTS_NAMESPACE
{
FORCEINLINE FString FilenameToTypeScriptVariableName(const FString& Filename)
{
FString TypeScriptVariable;
if (FChar::IsDigit(Filename[0]))
{
TypeScriptVariable.AppendChar('_');
}
for (TCHAR c : Filename)
{
if (FChar::IsAlnum(c) || c == '_' || c == '$' || FChar::IsAlpha(c))
{
if (c == '$')
{
TypeScriptVariable.AppendChar('$');
}
TypeScriptVariable.AppendChar(c);
}
else
{
TypeScriptVariable.AppendChar('$');
TypeScriptVariable.Append(FString::Printf(TEXT("%d"), (int) c));
TypeScriptVariable.AppendChar('$');
}
}
return TypeScriptVariable;
}
FORCEINLINE FString TypeScriptVariableNameToFilename(const FString& TypeScriptVariable)
{
FString Filename;
int32 i = 0;
if (TypeScriptVariable.StartsWith("_") && TypeScriptVariable.Len() > 1 && FChar::IsDigit(TypeScriptVariable[1]))
{
i = 1;
}
while (i < TypeScriptVariable.Len())
{
if (TypeScriptVariable[i] != '$')
{
Filename.AppendChar(TypeScriptVariable[i]);
++i;
}
else
{
if (i + 1 < TypeScriptVariable.Len() && TypeScriptVariable[i + 1] == '$')
{
Filename.AppendChar('$');
i += 2;
}
else
{
FString ascii_str;
++i;
while (i < TypeScriptVariable.Len() && FChar::IsDigit(TypeScriptVariable[i]))
{
ascii_str.AppendChar(TypeScriptVariable[i]);
++i;
}
if (i < TypeScriptVariable.Len() && TypeScriptVariable[i] == '$')
{
++i;
}
TCHAR original_char = static_cast<TCHAR>(FCString::Atoi(*ascii_str));
Filename.AppendChar(original_char);
}
}
}
return Filename;
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,577 @@
/*
* 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.
*/
#pragma once
#include <type_traits>
#include <string>
#include <cstring>
#include <functional>
#include <vector>
#include "pesapi.h"
#include "TypeInfo.hpp"
#define __DefObjectType_pesapi_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct is_objecttype<CLS> : public std::true_type \
{ \
}; \
}
#define __DefCDataPointerConverter_pesapi_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
namespace pesapi_impl \
{ \
template <> \
struct Converter<CLS*> \
{ \
static pesapi_value toScript(pesapi_env env, CLS* value) \
{ \
return pesapi_native_object_to_value(env, DynamicTypeId<CLS>::get(value), value, false); \
} \
static CLS* toCpp(pesapi_env env, pesapi_value value) \
{ \
return static_cast<CLS*>(pesapi_get_native_object_ptr(env, value)); \
} \
static bool accept(pesapi_env env, pesapi_value value) \
{ \
return pesapi_is_instance_of(env, StaticTypeId<CLS>::get(), value); \
} \
}; \
} \
}
namespace PUERTS_NAMESPACE
{
namespace pesapi_impl
{
template <typename T, typename Enable = void>
struct Converter;
template <typename T, typename = void>
struct CustomArgumentBufferType
{
static constexpr bool enable = false;
};
struct API
{
typedef pesapi_callback_info CallbackInfoType;
typedef pesapi_env ContextType;
typedef pesapi_value ValueType;
typedef void (*FunctionCallbackType)(pesapi_callback_info info);
typedef void* (*InitializeFuncType)(pesapi_callback_info Info);
struct GeneralFunctionInfo
{
const char* Name;
FunctionCallbackType Callback;
void* Data = nullptr;
const CFunctionInfo* ReflectionInfo = nullptr;
};
struct GeneralPropertyInfo
{
const char* Name;
FunctionCallbackType Getter;
FunctionCallbackType Setter;
void* Data = nullptr;
};
typedef NamedFunctionInfo GeneralFunctionReflectionInfo;
typedef NamedPropertyInfo GeneralPropertyReflectionInfo;
inline static int GetArgsLen(pesapi_callback_info info)
{
return pesapi_get_args_len(info);
}
inline static pesapi_value GetArg(pesapi_callback_info info, int index)
{
return pesapi_get_arg(info, index);
}
inline static pesapi_env GetContext(pesapi_callback_info info)
{
return pesapi_get_env(info);
}
inline static pesapi_value GetThis(pesapi_callback_info info)
{
return pesapi_get_this(info);
}
inline static pesapi_value GetHolder(pesapi_callback_info info)
{
return pesapi_get_holder(info);
}
// use where GetSelfFromData is true
inline static void* GetFunctionData(pesapi_callback_info info)
{
return pesapi_get_userdata(info);
}
inline static void ThrowException(pesapi_callback_info info, const char* msg)
{
pesapi_throw_by_string(info, msg);
}
inline static void SetReturn(pesapi_callback_info info, pesapi_value value)
{
pesapi_add_return(info, value);
}
template <typename T1, typename T2>
inline static void LinkOuter(pesapi_env env, pesapi_value outer, pesapi_value inner)
{
pesapi_set_property_uint32(env, inner, 0, outer);
}
inline static void UpdateRefValue(pesapi_env env, pesapi_value holder, pesapi_value value)
{
if (pesapi_is_object(env, holder))
{
pesapi_update_boxed_value(env, holder, value);
}
}
template <typename T>
inline static T* FastGetNativeObjectPointer(pesapi_env env, pesapi_value value)
{
return static_cast<T*>(pesapi_get_native_object_ptr(env, value));
}
inline static pesapi_value GetUndefined(pesapi_env env)
{
return pesapi_create_undefined(env);
}
inline static bool IsNullOrUndefined(pesapi_env env, pesapi_value val)
{
return pesapi_is_null(env, val) || pesapi_is_undefined(env, val);
}
typedef void (*FinalizeFuncType)(void* Ptr);
template <typename T, typename CDB>
static void Register(FinalizeFuncType Finalize, const CDB& Cdb)
{
size_t properties_count = Cdb.functions_.size() + Cdb.methods_.size() + Cdb.properties_.size() + Cdb.variables_.size();
auto properties = pesapi_alloc_property_descriptors(properties_count);
size_t pos = 0;
for (const auto& func : Cdb.functions_)
{
pesapi_set_method_info(properties, pos++, func.Name, true, func.Callback, nullptr, nullptr);
}
for (const auto& method : Cdb.methods_)
{
pesapi_set_method_info(properties, pos++, method.Name, false, method.Callback, nullptr, nullptr);
}
for (const auto& prop : Cdb.properties_)
{
pesapi_set_property_info(properties, pos++, prop.Name, false, prop.Getter, prop.Setter, nullptr, nullptr, nullptr);
}
for (const auto& prop : Cdb.variables_)
{
pesapi_set_property_info(properties, pos++, prop.Name, true, prop.Getter, prop.Setter, nullptr, nullptr, nullptr);
}
pesapi_finalize finalize = Finalize;
pesapi_define_class(StaticTypeId<T>::get(), Cdb.superTypeId_, Cdb.className_,
reinterpret_cast<InitializeFuncType>(Cdb.constructor_), finalize, properties_count, properties, nullptr);
static std::vector<NamedFunctionInfo> s_constructorInfos_{};
static std::vector<NamedFunctionInfo> s_methodInfos_{};
static std::vector<NamedFunctionInfo> s_functionInfos_{};
static std::vector<NamedPropertyInfo> s_propertyInfos_{};
static std::vector<NamedPropertyInfo> s_variableInfos_{};
s_constructorInfos_ = std::move(Cdb.constructorInfos_);
s_constructorInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_methodInfos_ = std::move(Cdb.methodInfos_);
s_methodInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_functionInfos_ = std::move(Cdb.functionInfos_);
s_functionInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
s_propertyInfos_ = std::move(Cdb.propertyInfos_);
s_propertyInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
s_variableInfos_ = std::move(Cdb.variableInfos_);
s_variableInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
pesapi_class_type_info(PUERTS_BINDING_PROTO_ID(), StaticTypeId<T>::get(), s_constructorInfos_.data(), s_methodInfos_.data(),
s_functionInfos_.data(), s_propertyInfos_.data(), s_variableInfos_.data());
}
template <typename T>
using Converter = Converter<T>;
template <typename T>
using CustomArgumentBufferType = CustomArgumentBufferType<T>;
};
class StringHolder
{
public:
StringHolder(pesapi_env env, pesapi_value value)
{
if (!value)
return;
if (pesapi_is_binary(env, value))
{
needFree_ = false;
size_t length = 0;
str_ = (char*) pesapi_get_value_binary(env, value, &length);
}
else
{
size_t length = 0;
str_ = (char*) pesapi_get_value_string_utf8(env, value, nullptr, &length);
needFree_ = false;
if (!str_)
{
str_ = new char[length + 1];
pesapi_get_value_string_utf8(env, value, str_, &length);
needFree_ = true;
}
}
}
// Disallow copying and assigning.
StringHolder(const StringHolder&) = delete;
void operator=(const StringHolder&) = delete;
~StringHolder()
{
if (needFree_ && str_)
{
delete[] str_;
}
}
const char* Data() const
{
return str_;
}
private:
char* str_;
bool needFree_;
};
template <>
struct CustomArgumentBufferType<const char*>
{
using type = StringHolder;
static constexpr bool enable = true;
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int64(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int64(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int64(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && !std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_uint64(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_uint64(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_uint64(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int32(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && !std::is_signed<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_uint32(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_uint32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_uint32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_int32(env, static_cast<int>(value));
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_int32(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_int32(env, value);
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_double(env, value);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return static_cast<T>(pesapi_get_value_double(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_double(env, value);
}
};
template <>
struct Converter<std::string>
{
static pesapi_value toScript(pesapi_env env, std::string value)
{
return pesapi_create_string_utf8(env, value.c_str(), value.size());
}
static std::string toCpp(pesapi_env env, pesapi_value value)
{
size_t bufSize = 0;
const char* str = pesapi_get_value_string_utf8(env, value, nullptr, &bufSize);
if (str)
{
return std::string(str);
}
else
{
std::vector<char> buffer(bufSize + 1);
str = pesapi_get_value_string_utf8(env, value, buffer.data(), &bufSize);
return std::string(str);
}
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_string(env, value);
}
};
template <>
struct Converter<const char*>
{
static pesapi_value toScript(pesapi_env env, const char* value)
{
return pesapi_create_string_utf8(env, value, strlen(value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_string(env, value);
}
};
template <>
struct Converter<void*>
{
static pesapi_value toScript(pesapi_env env, void* value)
{
return pesapi_create_binary(env, value, 0);
}
static void* toCpp(pesapi_env env, pesapi_value value)
{
size_t bufsize;
return pesapi_get_value_binary(env, value, &bufsize);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <>
struct Converter<bool>
{
static pesapi_value toScript(pesapi_env env, bool value)
{
return pesapi_create_boolean(env, value);
}
static bool toCpp(pesapi_env env, pesapi_value value)
{
return pesapi_get_value_bool(env, value);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boolean(env, value);
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<!is_objecttype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, const T& value)
{
return pesapi_boxing(env, Converter<T>::toScript(env, value));
}
static T toCpp(pesapi_env env, pesapi_value value)
{
return Converter<T>::toCpp(env, pesapi_unboxing(env, value));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boxed_value(env, value); // do not checked inner
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<is_objecttype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, const T& value)
{
return pesapi_boxing(env, Converter<T>::toScript(env, value));
}
static T* toCpp(pesapi_env env, pesapi_value value)
{
if (pesapi_is_object(env, value))
{
return Converter<T*>::toCpp(env, pesapi_unboxing(env, value));
}
return nullptr;
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_boxed_value(env, value); // do not checked inner
}
};
template <typename T>
struct Converter<T,
typename std::enable_if<is_script_type<typename std::remove_pointer<T>::type>::value && !std::is_array<T>::value &&
!std::is_const<typename std::remove_pointer<T>::type>::value && std::is_pointer<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_create_binary(env, value, 0);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
size_t bufsize;
return static_cast<T>(pesapi_get_value_binary(env, value, &bufsize));
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <typename T, std::size_t Size>
struct Converter<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value[Size])
{
return pesapi_create_binary(env, value, sizeof(T) * Size);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_binary(env, value);
}
};
template <class T>
struct Converter<T, typename std::enable_if<std::is_copy_constructible<T>::value && std::is_constructible<T>::value &&
is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static pesapi_value toScript(pesapi_env env, T value)
{
return pesapi_native_object_to_value(env, DynamicTypeId<T>::get(&value), new T(value), true);
}
static T toCpp(pesapi_env env, pesapi_value value)
{
T* ptr = (static_cast<T*>(pesapi_get_native_object_ptr(env, value)));
return ptr ? *ptr : T{};
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_instance_of(env, StaticTypeId<T>::get(), value);
}
};
} // namespace pesapi_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,281 @@
/*
* 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.
*/
#pragma once
#include "Binding.hpp"
#include "pesapi.h"
#include <iostream>
namespace PUERTS_NAMESPACE
{
namespace internal
{
class AutoValueScope
{
public:
AutoValueScope(pesapi_env_ref env_holder)
{
scope = pesapi_open_scope(env_holder);
}
~AutoValueScope()
{
pesapi_close_scope(scope);
}
pesapi_scope scope;
};
} // namespace internal
namespace pesapi_impl
{
static inline void REPORT_EXCEPTION(const char* MSG)
{
std::cout << "call function throw: " << MSG << std::endl;
}
class Object
{
public:
Object(pesapi_env env, pesapi_value value)
{
if (!env || !value || IsNullOrUndefined(env, value))
{
env_holder = nullptr;
value_holder = nullptr;
}
else
{
env_holder = pesapi_create_env_ref(env);
value_holder = pesapi_create_value_ref(env, value, 0);
}
}
Object(const Object& InOther)
{
if (!InOther.env_holder || !InOther.value_holder)
{
env_holder = nullptr;
value_holder = nullptr;
}
else
{
env_holder = pesapi_duplicate_env_ref(InOther.env_holder);
value_holder = pesapi_duplicate_value_ref(InOther.value_holder);
}
}
~Object()
{
if (!env_holder || !value_holder)
return;
pesapi_release_value_ref(value_holder);
pesapi_release_env_ref(env_holder);
}
template <typename T>
T Get(const char* key) const
{
if (!env_holder || !value_holder)
return {};
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto object = pesapi_get_value_from_ref(env, value_holder);
auto value = pesapi_get_property(env, object, key);
if (!pesapi_is_undefined(env, value))
{
return pesapi_impl::Converter<T>::toCpp(env, value);
}
return {};
}
template <typename T>
void Set(const char* key, T val) const
{
if (!env_holder || !value_holder)
return;
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto object = pesapi_get_value_from_ref(env, value_holder);
pesapi_set_property(env, object, key, pesapi_impl::Converter<T>::toScript(env, val));
}
bool IsValid() const
{
if (!env_holder || !value_holder)
return false;
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto val = pesapi_get_value_from_ref(env, value_holder);
return val && pesapi_is_object(env, val);
}
void operator=(const Object& obj)
{
env_holder = pesapi_duplicate_env_ref(obj.env_holder);
value_holder = pesapi_duplicate_value_ref(obj.value_holder);
}
pesapi_env_ref env_holder;
pesapi_value_ref value_holder;
friend struct pesapi_impl::Converter<Object>;
};
class Function : public Object
{
public:
Function(pesapi_env env, pesapi_value value) : Object(env, value)
{
}
template <typename... Args>
void Action(Args... cppArgs) const
{
if (!env_holder || !value_holder)
return;
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto object = pesapi_get_value_from_ref(env, value_holder);
auto _un_used = invokeHelper(env, object, cppArgs...);
if (pesapi_has_caught(ValueScope.scope))
{
REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true));
}
}
template <typename Ret, typename... Args>
Ret Func(Args... cppArgs) const
{
if (!env_holder || !value_holder)
return {};
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto object = pesapi_get_value_from_ref(env, value_holder);
auto ret = invokeHelper(env, object, cppArgs...);
if (pesapi_has_caught(ValueScope.scope))
{
REPORT_EXCEPTION(pesapi_get_exception_as_string(ValueScope.scope, true));
return {};
}
else
{
return pesapi_impl::Converter<Ret>::toCpp(env, ret);
}
}
bool IsValid() const
{
if (!env_holder || !value_holder)
return false;
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto val = pesapi_get_value_from_ref(env, value_holder);
return val && pesapi_is_function(env, val);
}
template <typename T>
void SetWeakAndOwnBy(const T* Owner)
{
internal::AutoValueScope ValueScope(env_holder);
auto env = pesapi_get_env_from_ref(env_holder);
auto owner = pesapi_native_object_to_value(env, StaticTypeId<T>::get(), Owner, false);
auto val = pesapi_get_value_from_ref(env, value_holder);
if (pesapi_set_owner(env, val, owner))
{
pesapi_set_ref_weak(env, value_holder);
}
}
private:
template <typename... Args>
auto invokeHelper(pesapi_env env, pesapi_value func, Args... CppArgs) const
{
pesapi_value argv[sizeof...(Args)]{pesapi_impl::Converter<Args>::toScript(env, CppArgs)...};
return pesapi_call_function(env, func, nullptr, sizeof...(Args), argv);
}
auto invokeHelper(pesapi_env env, pesapi_value func) const
{
return pesapi_call_function(env, func, nullptr, 0, nullptr);
}
friend struct pesapi_impl::Converter<Function>;
};
} // namespace pesapi_impl
template <>
struct ScriptTypeName<pesapi_impl::Object>
{
static constexpr auto value()
{
return internal::Literal("object");
}
};
template <>
struct ScriptTypeName<pesapi_impl::Function>
{
static constexpr auto value()
{
return internal::Literal("Function");
}
};
namespace pesapi_impl
{
template <>
struct Converter<Object>
{
static pesapi_value toScript(pesapi_env env, Object value)
{
return pesapi_get_value_from_ref(env, value.value_holder);
}
static Object toCpp(pesapi_env env, pesapi_value value)
{
return Object(env, value);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_object(env, value);
}
};
template <>
struct Converter<Function>
{
static pesapi_value toScript(pesapi_env env, Function value)
{
return pesapi_get_value_from_ref(env, value.value_holder);
}
static Function toCpp(pesapi_env env, pesapi_value value)
{
return Function(env, value);
}
static bool accept(pesapi_env env, pesapi_value value)
{
return pesapi_is_function(env, value);
}
};
#include "StdFunctionConverter.hpp"
} // namespace pesapi_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,150 @@
/*
* 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.
*/
#pragma once
#include "Runtime/Launch/Resources/Version.h"
#if ENGINE_MINOR_VERSION >= 25 || ENGINE_MAJOR_VERSION > 4
#define PropertyMacro FProperty
#define NumericPropertyMacro FNumericProperty
#define BytePropertyMacro FByteProperty
#define Int8PropertyMacro FInt8Property
#define Int16PropertyMacro FInt16Property
#define IntPropertyMacro FIntProperty
#define Int64PropertyMacro FInt64Property
#define UInt16PropertyMacro FUInt16Property
#define UInt32PropertyMacro FUInt32Property
#define UInt64PropertyMacro FUInt64Property
#define FloatPropertyMacro FFloatProperty
#define DoublePropertyMacro FDoubleProperty
#define BoolPropertyMacro FBoolProperty
#define ObjectPropertyBaseMacro FObjectPropertyBase
#define ObjectPropertyMacro FObjectProperty
#define WeakObjectPropertyMacro FWeakObjectProperty
#define LazyObjectPropertyMacro FLazyObjectProperty
#define SoftObjectPropertyMacro FSoftObjectProperty
#define ClassPropertyMacro FClassProperty
#define SoftClassPropertyMacro FSoftClassProperty
#define InterfacePropertyMacro FInterfaceProperty
#define NamePropertyMacro FNameProperty
#define StrPropertyMacro FStrProperty
#define ArrayPropertyMacro FArrayProperty
#define MapPropertyMacro FMapProperty
#define SetPropertyMacro FSetProperty
#define StructPropertyMacro FStructProperty
#define DelegatePropertyMacro FDelegateProperty
#define MulticastDelegatePropertyMacro FMulticastDelegateProperty
#define MulticastInlineDelegatePropertyMacro FMulticastInlineDelegateProperty
#define MulticastSparseDelegatePropertyMacro FMulticastSparseDelegateProperty
#define EnumPropertyMacro FEnumProperty
#define TextPropertyMacro FTextProperty
#define CastFieldMacro CastField
#else
#define PropertyMacro UProperty
#define NumericPropertyMacro UNumericProperty
#define BytePropertyMacro UByteProperty
#define Int8PropertyMacro UInt8Property
#define Int16PropertyMacro UInt16Property
#define IntPropertyMacro UIntProperty
#define Int64PropertyMacro UInt64Property
#define UInt16PropertyMacro UUInt16Property
#define UInt32PropertyMacro UUInt32Property
#define UInt64PropertyMacro UUInt64Property
#define FloatPropertyMacro UFloatProperty
#define DoublePropertyMacro UDoubleProperty
#define BoolPropertyMacro UBoolProperty
#define ObjectPropertyBaseMacro UObjectPropertyBase
#define ObjectPropertyMacro UObjectProperty
#define WeakObjectPropertyMacro UWeakObjectProperty
#define LazyObjectPropertyMacro ULazyObjectProperty
#define SoftObjectPropertyMacro USoftObjectProperty
#define ClassPropertyMacro UClassProperty
#define SoftClassPropertyMacro USoftClassProperty
#define InterfacePropertyMacro UInterfaceProperty
#define NamePropertyMacro UNameProperty
#define StrPropertyMacro UStrProperty
#define ArrayPropertyMacro UArrayProperty
#define MapPropertyMacro UMapProperty
#define SetPropertyMacro USetProperty
#define StructPropertyMacro UStructProperty
#define DelegatePropertyMacro UDelegateProperty
#define MulticastDelegatePropertyMacro UMulticastDelegateProperty
#define MulticastInlineDelegatePropertyMacro UMulticastInlineDelegateProperty
#define MulticastSparseDelegatePropertyMacro UMulticastSparseDelegateProperty
#define EnumPropertyMacro UEnumProperty
#define TextPropertyMacro UTextProperty
#define CastFieldMacro Cast
#endif
@@ -0,0 +1,46 @@
/*
* 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.
*/
#pragma once
#if !defined(PUERTS_NAMESPACE)
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
#define PUERTS_NAMESPACE puerts_qjs
#else
#define PUERTS_NAMESPACE puerts
#endif
#endif
#ifndef PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if defined(_MSC_VER)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(push)) __pragma(warning(disable : 4668))
#elif defined(__clang__)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS \
_Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wundef\"")
#elif defined(__GNUC__)
#define PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wundef\"")
#endif
#endif // PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#ifndef PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#if defined(_MSC_VER)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS __pragma(warning(pop))
#elif defined(__clang__)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS _Pragma("GCC diagnostic pop")
#endif
#endif // PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
#ifndef MSVC_PRAGMA
#if !defined(__clang__) && defined(_MSC_VER)
#define MSVC_PRAGMA(Pragma) __pragma(Pragma)
#else
#define MSVC_PRAGMA(...)
#endif
#endif
@@ -0,0 +1,168 @@
/*
* 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.
*/
#pragma once
#if defined(BUILDING_PES_EXTENSION)
#include "PesapiBackend.hpp"
#endif
#if !defined(BUILDING_PES_EXTENSION) || defined(PES_EXTENSION_WITH_V8_API)
#include "V8Backend.hpp"
#endif
#include "Object.hpp"
#ifndef PUERTS_BINDING_IMPL
#if defined(BUILDING_PES_EXTENSION) && !defined(PES_EXTENSION_WITH_V8_API)
#define PUERTS_BINDING_IMPL pesapi_impl
#else
#define PUERTS_BINDING_IMPL v8_impl
#endif
#endif
#define MakeConstructor(T, ...) \
::PUERTS_NAMESPACE::template ConstructorWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, T, ##__VA_ARGS__>
#define MakeGetter(M) &(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter)
#define MakeSetter(M) &(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::setter)
#define MakeProperty(M) \
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter), \
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::setter), \
::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
#define MakeReadonlyProperty(M) \
&(::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::getter), nullptr, \
::PUERTS_NAMESPACE::PropertyWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
#define MakeVariable(M) MakeProperty(M)
#define MakeReadonlyVariable(M) MakeReadonlyProperty(M)
#define MakeFunction(M, ...) \
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
{ \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::callWithDefaultValues( \
info, ##__VA_ARGS__); \
}, \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info( \
PUERTS_NAMESPACE::Count(__VA_ARGS__))
#define MakeExtension(M, ...) \
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
{ \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), \
M>::callExtensionWithDefaultValues(info, ##__VA_ARGS__); \
}, \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::extensionInfo( \
PUERTS_NAMESPACE::Count(__VA_ARGS__))
#define SelectFunction(SIGNATURE, M, ...) \
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
{ \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::callWithDefaultValues( \
info, ##__VA_ARGS__); \
}, \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::info( \
PUERTS_NAMESPACE::Count(__VA_ARGS__))
#define SelectFunction_PtrRet(SIGNATURE, M, ...) \
[](::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
{ \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, \
true>::callWithDefaultValues(info, ##__VA_ARGS__); \
}, \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, true>::info( \
PUERTS_NAMESPACE::Count(__VA_ARGS__))
#define MakeCheckFunction(M) \
&(::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::checkedCall), \
::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, decltype(M), M>::info()
#define MakeOverload(SIGNATURE, M) PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>
#define CombineOverloads(...) \
&::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::call, \
::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::length, \
::PUERTS_NAMESPACE::OverloadsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::infos()
#define CombineConstructors(...) \
&::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::call, \
::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::length, \
::PUERTS_NAMESPACE::ConstructorsCombiner<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, __VA_ARGS__>::infos()
#define DeclOverloads(Name) \
template <typename T> \
struct Name##PuertsOverloads \
{ \
};
#define DeclOverload(Name, SIGNATURE, M, ...) \
template <> \
struct Name##PuertsOverloads<SIGNATURE> \
{ \
static bool overloadCall(::PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API::CallbackInfoType info) \
{ \
return ::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M, \
true>::overloadCallWithDefaultValues(info, ##__VA_ARGS__); \
} \
static const ::PUERTS_NAMESPACE::CFunctionInfo* info() \
{ \
return ::PUERTS_NAMESPACE::FuncCallWrapper<PUERTS_NAMESPACE::PUERTS_BINDING_IMPL::API, SIGNATURE, M>::info( \
PUERTS_NAMESPACE::Count(__VA_ARGS__)); \
} \
};
#define SelectOverload(Name, SIGNATURE) Name##PuertsOverloads<SIGNATURE>
#define __DefObjectType_HELPER1(CLS, Suffix) __DefObjectType_##Suffix(CLS)
#define __DefObjectType_HELPER2(CLS, Suffix) __DefObjectType_HELPER1(CLS, Suffix)
#define __DefCDataPointerConverter_HELPER1(CLS, Suffix) __DefCDataPointerConverter_##Suffix(CLS)
#define __DefCDataPointerConverter_HELPER2(CLS, Suffix) __DefCDataPointerConverter_HELPER1(CLS, Suffix)
#define __DefObjectType(CLS) __DefObjectType_HELPER2(CLS, PUERTS_BINDING_IMPL)
#define __DefCDataPointerConverter(CLS) __DefCDataPointerConverter_HELPER2(CLS, PUERTS_BINDING_IMPL)
#define UsingNamedCppType(CLS, NAME) __DefScriptTTypeName(NAME, CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS)
#define UsingCppType(CLS) UsingNamedCppType(CLS, CLS)
#if defined(BUILDING_PES_EXTENSION) && !defined(PES_EXTENSION_WITH_V8_API)
#define UsingOtherModuleCppType(MODULE, CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct StaticTypeId<CLS> \
{ \
static const void* get() \
{ \
static void* cache_type_id = nullptr; \
if (!cache_type_id) \
{ \
cache_type_id = (void*) pesapi_find_type_id(#MODULE, #CLS); \
} \
return cache_type_id; \
} \
}; \
} \
UsingNamedCppType(CLS, CLS)
#endif
namespace PUERTS_NAMESPACE
{
template <typename T, typename API, typename RegisterAPI>
class ClassDefineBuilder;
#if defined(BUILDING_PES_EXTENSION)
template <typename T>
ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, pesapi_impl::API> DefineClass()
{
static auto NameLiteral = ScriptTypeName<T>::value();
return ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, pesapi_impl::API>(NameLiteral.Data());
}
#else
template <typename T>
ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, PUERTS_BINDING_IMPL::API> DefineClass()
{
static auto NameLiteral = ScriptTypeName<T>::value();
return ClassDefineBuilder<T, PUERTS_BINDING_IMPL::API, PUERTS_BINDING_IMPL::API>(NameLiteral.Data());
}
#endif
using Object = PUERTS_BINDING_IMPL::Object;
using Function = PUERTS_BINDING_IMPL::Function;
inline void ThrowException(const char* msg)
{
internal::ExceptionHandle<PUERTS_BINDING_IMPL::API>::Throw(msg);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,40 @@
/*
* 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.
*/
#pragma once
#if WITH_EDITOR
#include "CoreMinimal.h"
#include "IDirectoryWatcher.h"
#include "Misc/SecureHash.h"
#include <functional>
#include "PuertsNamespaceDef.h"
namespace PUERTS_NAMESPACE
{
class JSENV_API FSourceFileWatcher
{
public:
FSourceFileWatcher(std::function<void(const FString&)> InOnWatchedFileChanged);
~FSourceFileWatcher();
void OnSourceLoaded(const FString& InPath);
void OnDirectoryChanged(const TArray<FFileChangeData>& FileChanges);
private:
TMap<FString, FDelegateHandle> WatchedDirs;
TMap<FString, TMap<FString, FMD5Hash>> WatchedFiles;
FCriticalSection SourceFileWatcherCritical;
std::function<void(const FString&)> OnWatchedFileChanged;
};
} // namespace PUERTS_NAMESPACE
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
/*
* 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.
*/
#pragma once
template <typename R, typename... Args>
struct Converter<std::function<R(Args...)>>
{
static API::ValueType toScript(API::ContextType context, std::function<R(Args...)> value)
{
return API::GetUndefined(context);
}
static std::function<R(Args...)> toCpp(API::ContextType context, const API::ValueType value)
{
if (API::IsNullOrUndefined(context, value))
return nullptr;
Function PF(context, value);
return [=](Args... cppArgs) -> R { return PF.Func<R>(cppArgs...); };
}
static bool accept(API::ContextType context, const API::ValueType value)
{
return API::IsNullOrUndefined(context, value) || Converter<Function>::accept(context, value);
}
};
template <typename... Args>
struct Converter<std::function<void(Args...)>>
{
static API::ValueType toScript(API::ContextType context, std::function<void(Args...)> value)
{
return API::GetUndefined(context);
}
static std::function<void(Args...)> toCpp(API::ContextType context, const API::ValueType value)
{
if (API::IsNullOrUndefined(context, value))
return nullptr;
Function PF(context, value);
return [=](Args... cppArgs) -> void { PF.Action(cppArgs...); };
}
static bool accept(API::ContextType context, const API::ValueType value)
{
return API::IsNullOrUndefined(context, value) || Converter<Function>::accept(context, value);
}
};
@@ -0,0 +1,30 @@
/*
* 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.
*/
#pragma once
#include "UObject/Stack.h"
#include "UObject/Object.h"
#include "UObject/Class.h"
#include "PuertsNamespaceDef.h"
class UTypeScriptGeneratedClass;
namespace PUERTS_NAMESPACE
{
class ITsDynamicInvoker
{
public:
virtual void TsConstruct(UTypeScriptGeneratedClass* Class, UObject* Object) = 0;
virtual void InvokeTsMethod(UObject* ContextObject, UFunction* Function, FFrame& Stack, void* RESULT_PARAM) = 0;
virtual void NotifyReBind(UTypeScriptGeneratedClass* Class) = 0;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,536 @@
/*
* 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.
*/
#pragma once
#include <string>
#ifdef WITH_V8_FAST_CALL
#include "V8FastCall.hpp"
#endif
#include "PuertsNamespaceDef.h"
#define __DefScriptTTypeName(CLSNAME, CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct ScriptTypeName<CLS> \
{ \
static constexpr auto value() \
{ \
return internal::Literal(#CLSNAME); \
} \
}; \
}
#define PUERTS_BINDING_PROTO_ID() "fdq4falqlqcq"
#if defined(WITH_QJS_NAMESPACE_SUFFIX)
namespace v8_qjs
{
class CFunction;
}
namespace v8 = v8_qjs;
#else
namespace v8
{
class CFunction;
}
#endif
namespace PUERTS_NAMESPACE
{
namespace internal
{
template <std::size_t N>
class StringLiteral
{
public:
template <typename... Characters>
constexpr StringLiteral(Characters... characters) : m_value{characters..., '\0'}
{
}
template <std::size_t... Indexes>
constexpr StringLiteral(const char (&value)[N + 1], std::index_sequence<Indexes...> dummy) : StringLiteral(value[Indexes]...)
{
}
constexpr StringLiteral(const char (&value)[N + 1]) : StringLiteral(value, std::make_index_sequence<N>{})
{
}
constexpr char operator[](const std::size_t index) const
{
return m_value[index];
}
constexpr const char* Data() const
{
return m_value;
}
template <std::size_t Start, std::size_t... Index>
constexpr StringLiteral<N - Start> Sub(std::index_sequence<Index...> dummy) const
{
return StringLiteral<N - Start>(m_value[Start + Index]...);
}
template <std::size_t Start>
constexpr StringLiteral<N - Start> Sub() const
{
return Sub<Start>(std::make_index_sequence<N - Start>());
}
private:
const char m_value[N + 1];
};
template <typename Left, typename Right, std::size_t... IndexesLeft, std::size_t... IndexesRight>
constexpr StringLiteral<sizeof...(IndexesLeft) + sizeof...(IndexesRight)> ConcatStrings(
const Left& lhs, const Right& rhs, std::index_sequence<IndexesLeft...> dummy1, std::index_sequence<IndexesRight...> dummy2)
{
return StringLiteral<sizeof...(IndexesLeft) + sizeof...(IndexesRight)>(lhs[IndexesLeft]..., rhs[IndexesRight]...);
}
template <std::size_t X, std::size_t Y>
constexpr StringLiteral<X + Y> operator+(const StringLiteral<X>& lhs, const StringLiteral<Y>& rhs)
{
return ConcatStrings(lhs, rhs, std::make_index_sequence<X>(), std::make_index_sequence<Y>());
}
template <std::size_t N>
constexpr auto Literal(const char (&value)[N])
{
return StringLiteral<N - 1>(value, typename std::make_index_sequence<N - 1>{});
}
} // namespace internal
template <typename T, typename Enable = void>
struct ScriptTypeName
{
};
template <typename T, typename Enable = void>
struct ScriptTypeNameWithNamespace
{
static constexpr auto value()
{
return ScriptTypeName<T>::value();
}
};
template <typename T>
struct ScriptTypeName<T*>
{
static constexpr auto value()
{
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
}
};
template <typename T>
struct ScriptTypeName<T&>
{
static constexpr auto value()
{
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
}
};
template <typename T>
struct ScriptTypeName<T&&>
{
static constexpr auto value()
{
return ScriptTypeName<typename std::remove_cv<T>::type>::value();
}
};
template <typename T>
struct ScriptTypeName<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8>::type>
{
static constexpr auto value()
{
return internal::Literal("bigint");
}
};
template <typename T>
struct ScriptTypeName<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
static constexpr auto value()
{
return internal::Literal("number");
}
};
template <typename T>
struct ScriptTypeName<T,
typename std::enable_if<std::is_floating_point<T>::value || (std::is_integral<T>::value && sizeof(T) < 8)>::type>
{
static constexpr auto value()
{
return internal::Literal("number");
}
};
template <>
struct ScriptTypeName<std::string>
{
static constexpr auto value()
{
return internal::Literal("string");
}
};
template <>
struct ScriptTypeName<const char*>
{
static constexpr auto value()
{
return internal::Literal("cstring");
}
};
template <>
struct ScriptTypeName<bool>
{
static constexpr auto value()
{
return internal::Literal("boolean");
}
};
template <>
struct ScriptTypeName<void>
{
static constexpr auto value()
{
return internal::Literal("void");
}
};
template <typename T>
struct StaticTypeId
{
static const void* get()
{
static T* dummy = nullptr;
return &dummy;
}
};
template <typename T, typename Enable = void>
struct DynamicTypeId
{
static const void* get(T* Obj)
{
return StaticTypeId<T>::get();
}
};
template <typename T>
struct is_uetype : std::false_type
{
};
template <typename T>
struct is_objecttype : std::false_type
{
};
template <typename T, typename Enable = void>
struct is_script_type : std::false_type
{
};
template <typename T>
struct is_script_type<T, typename std::enable_if<std::is_fundamental<T>::value && !std::is_same<T, void>::value>::type>
: std::true_type
{
};
template <>
struct is_script_type<std::string> : std::true_type
{
};
template <typename T, size_t Size>
struct ScriptTypeName<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
static constexpr auto value()
{
return internal::Literal("ArrayBuffer");
}
};
template <>
struct ScriptTypeName<void*>
{
static constexpr auto value()
{
return internal::Literal("any");
}
};
template <>
struct ScriptTypeName<const void*>
{
static constexpr auto value()
{
return internal::Literal("any");
}
};
class CTypeInfo
{
public:
virtual const char* Name() const = 0;
virtual bool IsPointer() const = 0;
virtual bool IsRef() const = 0;
virtual bool IsConst() const = 0;
virtual bool IsUEType() const = 0;
virtual bool IsObjectType() const = 0;
};
class CFunctionInfo
{
public:
virtual const CTypeInfo* Return() const = 0;
virtual unsigned int ArgumentCount() const = 0;
virtual unsigned int DefaultCount() const = 0;
virtual const CTypeInfo* Argument(unsigned int index) const = 0;
virtual const char* CustomSignature() const = 0;
virtual const class v8::CFunction* FastCallInfo() const = 0;
};
template <typename T, bool ScriptTypePtrAsRef>
class CTypeInfoImpl : CTypeInfo
{
public:
virtual const char* Name() const override
{
static auto NameLiteral = ScriptTypeName<T>::value();
return NameLiteral.Data();
}
virtual bool IsPointer() const override
{
return std::is_pointer<T>::value && !ScriptTypePtrAsRef;
};
virtual bool IsRef() const override
{
return (std::is_reference<T>::value && !std::is_const<typename std::remove_reference<T>::type>::value) ||
(std::is_pointer<T>::value &&
!std::is_same<void, typename std::decay<typename std::remove_pointer<T>::type>::type>::value &&
!std::is_same<char, typename std::decay<typename std::remove_pointer<T>::type>::type>::value &&
ScriptTypePtrAsRef && !IsUEType() && !IsObjectType());
};
virtual bool IsConst() const override
{
return std::is_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::value;
};
virtual bool IsUEType() const override
{
return is_uetype<typename std::remove_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::type>::value;
};
virtual bool IsObjectType() const override
{
return is_objecttype<
typename std::remove_const<typename std::remove_pointer<typename std::decay<T>::type>::type>::type>::value;
};
static const CTypeInfo* get()
{
static CTypeInfoImpl instance;
return &instance;
}
};
template <typename Ret, bool ScriptTypePtrAsRef, std::size_t StartParameter, typename... Args>
class CFunctionInfoImpl : public CFunctionInfo
{
protected:
const CTypeInfo* return_;
const unsigned int argCount_;
const CTypeInfo* arguments_[sizeof...(Args) + 1];
unsigned int defaultCount_;
CFunctionInfoImpl()
: return_(CTypeInfoImpl<Ret, ScriptTypePtrAsRef>::get())
, argCount_(sizeof...(Args))
, arguments_{CTypeInfoImpl<Args, ScriptTypePtrAsRef>::get()...}
, defaultCount_(0)
{
}
virtual ~CFunctionInfoImpl()
{
}
public:
virtual const CTypeInfo* Return() const override
{
return return_;
}
virtual unsigned int ArgumentCount() const override
{
return argCount_ - StartParameter;
}
virtual unsigned int DefaultCount() const override
{
return defaultCount_;
}
virtual const CTypeInfo* Argument(unsigned int index) const override
{
return arguments_[index + StartParameter];
}
virtual const char* CustomSignature() const override
{
return nullptr;
}
virtual const class v8::CFunction* FastCallInfo() const override
{
return nullptr;
};
static const CFunctionInfo* get(unsigned int defaultCount)
{
static CFunctionInfoImpl instance{};
instance.defaultCount_ = defaultCount;
return &instance;
}
};
template <typename T, T, bool, std::size_t StartParameter = 0>
class CFunctionInfoByPtrImpl
{
};
template <typename Ret, typename... Args, Ret (*func)(Args...), bool ScriptTypePtrAsRef, std::size_t StartParameter>
class CFunctionInfoByPtrImpl<Ret (*)(Args...), func, ScriptTypePtrAsRef, StartParameter>
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, StartParameter, Args...>
{
public:
virtual ~CFunctionInfoByPtrImpl()
{
}
#ifdef WITH_V8_FAST_CALL
virtual const class v8::CFunction* FastCallInfo() const override
{
return V8FastCall<Ret (*)(Args...), func>::info();
};
#endif
static const CFunctionInfo* get(unsigned int defaultCount)
{
static CFunctionInfoByPtrImpl instance{};
instance.defaultCount_ = defaultCount;
return &instance;
}
};
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...), bool ScriptTypePtrAsRef>
class CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...), func, ScriptTypePtrAsRef>
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, 0, Args...>
{
public:
virtual ~CFunctionInfoByPtrImpl()
{
}
#ifdef WITH_V8_FAST_CALL
virtual const class v8::CFunction* FastCallInfo() const override
{
return V8FastCall<Ret (Inc::*)(Args...), func>::info();
};
#endif
static const CFunctionInfo* get(unsigned int defaultCount)
{
static CFunctionInfoByPtrImpl instance{};
instance.defaultCount_ = defaultCount;
return &instance;
}
};
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...) const, bool ScriptTypePtrAsRef>
class CFunctionInfoByPtrImpl<Ret (Inc::*)(Args...) const, func, ScriptTypePtrAsRef>
: public CFunctionInfoImpl<Ret, ScriptTypePtrAsRef, 0, Args...>
{
public:
virtual ~CFunctionInfoByPtrImpl()
{
}
#ifdef WITH_V8_FAST_CALL
virtual const class v8::CFunction* FastCallInfo() const override
{
return V8FastCall<Ret (Inc::*)(Args...) const, func>::info();
};
#endif
static const CFunctionInfo* get(unsigned int defaultCount)
{
static CFunctionInfoByPtrImpl instance{};
instance.defaultCount_ = defaultCount;
return &instance;
}
};
class CFunctionInfoWithCustomSignature : public CFunctionInfo
{
const char* _signature;
public:
CFunctionInfoWithCustomSignature(const char* signature) : _signature(signature)
{
}
virtual ~CFunctionInfoWithCustomSignature()
{
}
virtual const CTypeInfo* Return() const override
{
return nullptr;
}
virtual unsigned int ArgumentCount() const override
{
return 0;
}
virtual unsigned int DefaultCount() const override
{
return 0;
}
virtual const CTypeInfo* Argument(unsigned int index) const override
{
return nullptr;
}
virtual const char* CustomSignature() const override
{
return _signature;
}
virtual const class v8::CFunction* FastCallInfo() const override
{
return nullptr;
};
};
struct NamedFunctionInfo
{
const char* Name;
const CFunctionInfo* Type;
};
struct NamedPropertyInfo
{
const char* Name;
const CTypeInfo* Type;
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,27 @@
/*
* 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.
*/
#pragma once
#include "CoreMinimal.h"
#include "Engine/Blueprint.h"
#include "TypeScriptBlueprint.generated.h"
/**
*
*/
UCLASS()
class JSENV_API UTypeScriptBlueprint : public UBlueprint
{
GENERATED_BODY()
public:
#if WITH_EDITOR
virtual UClass* GetBlueprintClass() const override;
#endif
};
@@ -0,0 +1,74 @@
/*
* 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.
*/
#pragma once
#include "TsDynamicInvoker.h"
#include "CoreMinimal.h"
#include "Engine/BlueprintGeneratedClass.h"
#include "Templates/Function.h"
#include "Templates/SharedPointer.h"
#include "Runtime/CoreUObject/Public/UObject/Package.h"
#include "TypeScriptGeneratedClass.generated.h"
struct PendingConstructJobInfo
{
TFunction<void()> Func = nullptr;
TSharedPtr<int> Ref = nullptr;
};
/**
*
*/
UCLASS()
class JSENV_API UTypeScriptGeneratedClass : public UBlueprintGeneratedClass
{
GENERATED_BODY()
public:
TWeakPtr<PUERTS_NAMESPACE::ITsDynamicInvoker, ESPMode::ThreadSafe> DynamicInvoker;
TSet<FName> FunctionToRedirect;
bool RedirectedToTypeScript = false;
TMap<FName, FNativeFuncPtr> TempNativeFuncStorage;
#if WITH_EDITOR
bool NeedReBind = true;
TSet<TWeakObjectPtr<UObject>> GeneratedObjects;
bool FunctionToRedirectInitialized = false;
static void NotifyRebind(UClass* Class);
void LazyLoadRedirect();
#endif
DECLARE_FUNCTION(execLazyLoadCallJS);
static void StaticConstructor(const FObjectInitializer& ObjectInitializer);
void ObjectInitialize(const FObjectInitializer& ObjectInitializer);
virtual void Bind() override;
void RedirectToTypeScript(UFunction* InFunction);
void RedirectToTypeScriptFinish();
void CancelRedirection();
bool NotSupportInject();
void RestoreNativeFunc();
UPROPERTY()
bool HasConstructor;
DECLARE_FUNCTION(execCallJS);
};
@@ -0,0 +1,58 @@
/*
* 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.
*/
#pragma once
#include "Runtime/Launch/Resources/Version.h"
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UObject/UObjectIterator.h"
#include "PuertsNamespaceDef.h"
namespace PUERTS_NAMESPACE
{
FORCEINLINE bool UEObjectIsPendingKill(const UObject* Test)
{
#if ENGINE_MAJOR_VERSION > 4
return !IsValid(Test) || Test->IsUnreachable();
#else
return Test->IsPendingKillOrUnreachable();
#endif
}
#if ENGINE_MAJOR_VERSION > 4
#define FUETicker FTSTicker
#define FUETickDelegateHandle FTSTicker::FDelegateHandle
#else
#define FUETicker FTicker
#define FUETickDelegateHandle FDelegateHandle
#endif
#if ENGINE_MINOR_VERSION >= 27 || ENGINE_MAJOR_VERSION > 4
typedef FThreadSafeObjectIterator FUEObjectIterator;
#else
typedef FObjectIterator FUEObjectIterator;
#endif
template <typename T>
T* FindAnyType(const TCHAR* InShortName)
{
#if (ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 1) || ENGINE_MAJOR_VERSION > 5
return FindFirstObject<T>(
InShortName, EFindFirstObjectOptions::EnsureIfAmbiguous | EFindFirstObjectOptions::NativeFirst, ELogVerbosity::Error);
#else
return FindObject<T>(ANY_PACKAGE, InShortName);
#endif
}
template <typename T>
T* FindAnyType(const FString& InShortName)
{
return FindAnyType<T>(*InShortName);
}
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,534 @@
/*
* 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.
*/
#pragma once
#include "ScriptBackend.hpp"
#include "DataTransfer.h"
#include "ArrayBuffer.h"
#include "UECompatible.h"
#include "PuertsNamespaceDef.h"
#define UsingUClass(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct ScriptTypeName<CLS> \
{ \
static constexpr auto value() \
{ \
return internal::Literal(#CLS).Sub<1>(); \
} \
}; \
} \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct is_uetype<CLS> : public std::true_type \
{ \
}; \
}
#define UsingTArrayWithName(CLS, CLSNAME) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct ScriptTypeName<TArray<CLS>> \
{ \
static constexpr auto value() \
{ \
return internal::Literal(CLSNAME); \
} \
}; \
} \
__DefObjectType(TArray<CLS>) __DefCDataPointerConverter(TArray<CLS>)
#define UsingCrossModuleCppType(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct StaticTypeId<CLS> \
{ \
static const void* get() \
{ \
static const void* cache_type_id = nullptr; \
if (!cache_type_id) \
{ \
auto info = PUERTS_NAMESPACE::FindCppTypeClassByName(#CLS); \
cache_type_id = info ? info->TypeId : &cache_type_id; \
} \
return cache_type_id; \
} \
}; \
} \
UsingNamedCppType(CLS, CLS)
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 4
#define RegisterTArray(CLS) \
PUERTS_NAMESPACE::DefineClass<TArray<CLS>>() \
.Method("Add", SelectFunction(int (TArray<CLS>::*)(CLS const&), &TArray<CLS>::Add)) \
.Method("Get", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
.Method("GetRef", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
.Method("Num", MakeFunction(&TArray<CLS>::Num)) \
.Method("Contains", MakeFunction(&TArray<CLS>::Contains<CLS>)) \
.Method("FindIndex", SelectFunction(int (TArray<CLS>::*)(CLS const&) const, &TArray<CLS>::Find)) \
.Method( \
"RemoveAt", SelectFunction(void (TArray<CLS>::*)(int, /* New param in 5.4*/ EAllowShrinking), &TArray<CLS>::RemoveAt)) \
.Method("IsValidIndex", MakeFunction(&TArray<CLS>::IsValidIndex)) \
.Method("Empty", MakeFunction(&TArray<CLS>::Empty)) \
.Register()
#else
#define RegisterTArray(CLS) \
PUERTS_NAMESPACE::DefineClass<TArray<CLS>>() \
.Method("Add", SelectFunction(int (TArray<CLS>::*)(CLS const&), &TArray<CLS>::Add)) \
.Method("Get", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
.Method("GetRef", SelectFunction(CLS& (TArray<CLS>::*) (int), &TArray<CLS>::operator[])) \
.Method("Num", MakeFunction(&TArray<CLS>::Num)) \
.Method("Contains", MakeFunction(&TArray<CLS>::Contains<CLS>)) \
.Method("FindIndex", SelectFunction(int (TArray<CLS>::*)(CLS const&) const, &TArray<CLS>::Find)) \
.Method("RemoveAt", SelectFunction(void (TArray<CLS>::*)(int), &TArray<CLS>::RemoveAt)) \
.Method("IsValidIndex", MakeFunction(&TArray<CLS>::IsValidIndex)) \
.Method("Empty", MakeFunction(&TArray<CLS>::Empty)) \
.Register()
#endif
#define UsingUStruct(CLS) UsingUClass(CLS)
#define UsingContainer(CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS)
#define UsingTSharedPtr(ITEMCLS) __DefObjectType(TSharedPtr<ITEMCLS>) __DefCDataPointerConverter(TSharedPtr<ITEMCLS>)
template <class T>
struct TSharedPtrExtension
{
static bool Equals(const TSharedPtr<T> Lhs, const TSharedPtr<T> Rhs)
{
return Lhs == Rhs;
}
};
#define RegisterTSharedPtr(ITEMCLS) \
PUERTS_NAMESPACE::DefineClass<TSharedPtr<ITEMCLS>>() \
.Method("Equals", MakeExtension(&TSharedPtrExtension<ITEMCLS>::Equals)) \
.Register();
namespace PUERTS_NAMESPACE
{
namespace v8_impl
{
class TCharStringHolder
{
public:
TCharStringHolder()
{
}
TCharStringHolder(v8::Local<v8::Context> context, const v8::Local<v8::Value> value)
{
Str = FV8Utils::ToFString(context->GetIsolate(), value);
}
const TCHAR* Data() const
{
return *Str;
}
private:
FString Str;
};
template <>
struct CustomArgumentBufferType<const TCHAR*>
{
using type = TCharStringHolder;
static constexpr bool enable = true;
};
template <>
struct Converter<FString>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FString value)
{
return FV8Utils::ToV8String(context->GetIsolate(), value);
}
static FString toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return FV8Utils::ToFString(context->GetIsolate(), value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<FName>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FName value)
{
return FV8Utils::ToV8String(context->GetIsolate(), value.ToString());
}
static FName toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
size_t ByteLength;
auto Data = DataTransfer::GetArrayBufferData(Ab, ByteLength);
if (ByteLength == sizeof(FName))
{
return *static_cast<FName*>(Data);
}
}
return FV8Utils::ToFName(context->GetIsolate(), value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<const TCHAR*>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const TCHAR* value)
{
return FV8Utils::ToV8String(context->GetIsolate(), value);
}
static TCharStringHolder toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return TCharStringHolder(context, value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
#ifndef PUERTS_FTEXT_AS_OBJECT
template <>
struct Converter<FText>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FText value)
{
return FV8Utils::ToV8String(context->GetIsolate(), value.ToString());
}
static FText toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return FText::FromString(FV8Utils::ToFString(context->GetIsolate(), value));
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
#endif
template <>
struct Converter<FArrayBuffer>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FArrayBuffer value)
{
return DataTransfer::NewArrayBuffer(context, value.Data, value.Length);
}
static FArrayBuffer toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
FArrayBuffer Ret = {nullptr, 0};
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
Ret.Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
Ret.Length = BuffView->ByteLength();
}
else if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
size_t ByteLength;
Ret.Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab, ByteLength));
Ret.Length = ByteLength;
}
return Ret;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <>
struct Converter<FArrayBufferValue>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, FArrayBufferValue& value)
{
v8::Local<v8::ArrayBuffer> Ab = v8::ArrayBuffer::New(context->GetIsolate(), value.Data.Num());
void* Buff = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab));
::memcpy(Buff, value.Data.GetData(), value.Data.Num());
return Ab;
}
static FArrayBufferValue toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
FArrayBufferValue Ret;
size_t Len = 0;
void* Data = nullptr;
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
Data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
Len = BuffView->ByteLength();
}
else if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
Data = DataTransfer::GetArrayBufferData(Ab, Len);
}
if (Len > 0 && Data)
{
Ret.Data.AddUninitialized(Len);
::memcpy(Ret.Data.GetData(), Data, Len);
}
return Ret;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <typename T>
struct Converter<T*, typename std::enable_if<std::is_convertible<T*, const UObject*>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
{
using TypeWithoutConst = typename std::remove_const<T>::type;
return DataTransfer::FindOrAddObject<TypeWithoutConst>(context->GetIsolate(), context, (TypeWithoutConst*) (value));
}
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
T* Ret = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast() || UEObjectIsPendingKill(Ret)) ? nullptr
: Ret;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value.As<v8::Object>()->IsNullOrUndefined())
return true;
return DataTransfer::IsInstanceOf(context->GetIsolate(), T::StaticClass(), value.As<v8::Object>());
}
};
template <typename T>
struct Converter<T*, typename std::enable_if<!std::is_convertible<T*, const UObject*>::value &&
std::is_convertible<T*, const UObjectBase*>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
{
return DataTransfer::FindOrAddObject<UObject>(context->GetIsolate(), context, static_cast<UObject*>(value));
}
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
T* Ret = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast()) ? nullptr : Ret;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::IsInstanceOf(context->GetIsolate(), UObject::StaticClass(), value.As<v8::Object>());
}
};
} // namespace v8_impl
template <>
struct ScriptTypeName<FString>
{
static constexpr auto value()
{
return internal::Literal("string");
}
};
template <>
struct ScriptTypeName<FName>
{
static constexpr auto value()
{
return internal::Literal("string");
}
};
template <>
struct ScriptTypeName<const TCHAR*>
{
static constexpr auto value()
{
return internal::Literal("string");
}
};
#ifndef PUERTS_FTEXT_AS_OBJECT
template <>
struct ScriptTypeName<FText>
{
static constexpr auto value()
{
return internal::Literal("string");
}
};
#endif
template <>
struct ScriptTypeName<FArrayBuffer>
{
static constexpr auto value()
{
return internal::Literal("ArrayBuffer");
}
};
template <>
struct ScriptTypeName<FArrayBufferValue>
{
static constexpr auto value()
{
return internal::Literal("ArrayBuffer");
}
};
template <typename T>
struct ScriptTypeNameWithNamespace<T,
typename std::enable_if<is_objecttype<typename std::remove_pointer<typename std::decay<T>::type>::type>::value>::type>
{
static constexpr auto value()
{
return internal::Literal("cpp.") + ScriptTypeName<T>::value();
}
};
template <typename T>
struct ScriptTypeNameWithNamespace<T,
typename std::enable_if<is_uetype<typename std::remove_pointer<typename std::decay<T>::type>::type>::value>::type>
{
static constexpr auto value()
{
return internal::Literal("UE.") + ScriptTypeName<T>::value();
}
};
template <typename T>
struct ScriptTypeName<TSharedPtr<T>>
{
static constexpr auto value()
{
return internal::Literal("UE.TSharedPtr<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
}
};
template <typename T>
struct ScriptTypeName<TArray<T>>
{
static constexpr auto value()
{
return internal::Literal("UE.TArray<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
}
};
template <typename T>
struct ScriptTypeName<TSet<T>>
{
static constexpr auto value()
{
return internal::Literal("UE.TSet<") + ScriptTypeNameWithNamespace<T>::value() + internal::Literal(">");
}
};
template <typename TKey, typename TValue>
struct ScriptTypeName<TMap<TKey, TValue>>
{
static constexpr auto value()
{
return internal::Literal("UE.TMap<") + ScriptTypeNameWithNamespace<TKey>::value() + internal::Literal(", ") +
ScriptTypeNameWithNamespace<TValue>::value() + internal::Literal(">");
}
};
namespace internal
{
template <typename T, typename = void>
struct IsUStructHelper : std::false_type
{
};
template <typename T>
struct IsUStructHelper<T, Void_t<decltype(&TScriptStructTraits<T>::Get)>> : std::true_type
{
};
} // namespace internal
namespace v8_impl
{
template <typename T>
struct Converter<T*,
typename std::enable_if<!std::is_convertible<T*, const UObject*>::value && internal::IsUStructHelper<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T* value)
{
return DataTransfer::FindOrAddStruct<T>(context->GetIsolate(), context, (void*) value, true);
}
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::IsInstanceOf<T>(context->GetIsolate(), value.As<v8::Object>());
}
};
template <typename T>
struct Converter<T, typename std::enable_if<internal::IsUStructHelper<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return DataTransfer::FindOrAddStruct<T>(context->GetIsolate(), context, new T(value), false);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
T* ptr = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
return ptr ? *ptr : T{};
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::IsInstanceOf<T>(context->GetIsolate(), value.As<v8::Object>());
}
};
} // namespace v8_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,643 @@
/*
* 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.
*/
#pragma once
#include <type_traits>
#include <string>
#include <functional>
#include "DataTransfer.h"
#include "JSClassRegister.h"
#define __DefObjectType_v8_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
template <> \
struct is_objecttype<CLS> : public std::true_type \
{ \
}; \
}
#define __DefCDataPointerConverter_v8_impl(CLS) \
namespace PUERTS_NAMESPACE \
{ \
namespace v8_impl \
{ \
template <> \
struct Converter<CLS*> \
{ \
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, CLS* value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::FindOrAddCData( \
context->GetIsolate(), context, DynamicTypeId<CLS>::get(value), value, true); \
} \
static CLS* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::GetPointerFast<CLS>(value.As<v8::Object>()); \
} \
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value) \
{ \
return ::PUERTS_NAMESPACE::DataTransfer::IsInstanceOf( \
context->GetIsolate(), StaticTypeId<CLS>::get(), value.As<v8::Object>()); \
} \
}; \
} \
}
namespace PUERTS_NAMESPACE
{
namespace v8_impl
{
template <typename T, typename Enable = void>
struct Converter;
template <typename T, typename = void>
struct CustomArgumentBufferType
{
static constexpr bool enable = false;
};
struct API
{
typedef const v8::FunctionCallbackInfo<v8::Value>& CallbackInfoType;
typedef v8::Local<v8::Context> ContextType;
typedef v8::Local<v8::Value> ValueType;
typedef v8::FunctionCallback FunctionCallbackType;
typedef void* (*InitializeFuncType)(const v8::FunctionCallbackInfo<v8::Value>& Info);
typedef void (*FinalizeFuncType)(void* Ptr, void* ClassData, void* EnvData);
typedef JSFunctionInfo GeneralFunctionInfo;
typedef JSPropertyInfo GeneralPropertyInfo;
typedef NamedFunctionInfo GeneralFunctionReflectionInfo;
typedef NamedPropertyInfo GeneralPropertyReflectionInfo;
V8_INLINE static int GetArgsLen(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.Length();
}
V8_INLINE static v8::Local<v8::Value> GetArg(const v8::FunctionCallbackInfo<v8::Value>& info, int index)
{
return info[index];
}
V8_INLINE static v8::Local<v8::Context> GetContext(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.GetIsolate()->GetCurrentContext();
}
V8_INLINE static v8::Local<v8::Object> GetThis(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.This();
}
V8_INLINE static v8::Local<v8::Object> GetHolder(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return info.Holder();
}
// use where GetSelfFromData is true
V8_INLINE static void* GetFunctionData(const v8::FunctionCallbackInfo<v8::Value>& info)
{
return v8::Local<v8::External>::Cast(info.Data())->Value();
}
V8_INLINE static void ThrowException(const v8::FunctionCallbackInfo<v8::Value>& info, const char* msg)
{
v8::Isolate* isolate = info.GetIsolate();
isolate->ThrowException(
v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg, v8::NewStringType::kNormal).ToLocalChecked()));
}
V8_INLINE static void SetReturn(const v8::FunctionCallbackInfo<v8::Value>& info, v8::Local<v8::Value> value)
{
info.GetReturnValue().Set(value);
}
template <typename T1, typename T2>
V8_INLINE static void LinkOuter(v8::Local<v8::Context> Context, v8::Local<v8::Value> Outer, v8::Local<v8::Value> Inner)
{
LinkOuterImpl(Context, Outer, Inner);
}
V8_INLINE static void UpdateRefValue(v8::Local<v8::Context> context, v8::Local<v8::Value> holder, v8::Local<v8::Value> value)
{
if (holder->IsObject())
{
auto outer = holder->ToObject(context).ToLocalChecked();
(void) (outer->Set(context, 0, value));
}
}
template <typename T>
V8_INLINE static T* FastGetNativeObjectPointer(v8::Local<v8::Context> context, v8::Local<v8::Object> Object)
{
return DataTransfer::GetPointerFast<T>(Object);
}
V8_INLINE static v8::Local<v8::Value> GetUndefined(v8::Local<v8::Context> context)
{
return v8::Undefined(context->GetIsolate());
}
V8_INLINE static bool IsNullOrUndefined(v8::Local<v8::Context> context, v8::Local<v8::Value> val)
{
return val->IsNullOrUndefined();
}
template <typename T, typename CDB>
static void Register(FinalizeFuncType Finalize, const CDB& Cdb)
{
const bool isUEType = is_uetype<T>::value;
static std::vector<JSFunctionInfo> s_functions_{};
static std::vector<JSFunctionInfo> s_methods_{};
static std::vector<JSPropertyInfo> s_properties_{};
static std::vector<JSPropertyInfo> s_variables_{};
static std::vector<NamedFunctionInfo> s_constructorInfos_{};
static std::vector<NamedFunctionInfo> s_methodInfos_{};
static std::vector<NamedFunctionInfo> s_functionInfos_{};
static std::vector<NamedPropertyInfo> s_propertyInfos_{};
static std::vector<NamedPropertyInfo> s_variableInfos_{};
JSClassDefinition ClassDef = JSClassEmptyDefinition;
if (isUEType)
{
ClassDef.UETypeName = Cdb.className_;
}
else
{
ClassDef.ScriptName = Cdb.className_;
ClassDef.TypeId = StaticTypeId<T>::get();
ClassDef.SuperTypeId = Cdb.superTypeId_;
}
ClassDef.SetInitialize(Cdb.constructor_);
ClassDef.Finalize = Finalize;
s_functions_ = std::move(Cdb.functions_);
s_functions_.push_back(JSFunctionInfo());
ClassDef.Functions = s_functions_.data();
s_methods_ = std::move(Cdb.methods_);
s_methods_.push_back(JSFunctionInfo());
ClassDef.Methods = s_methods_.data();
s_properties_ = std::move(Cdb.properties_);
s_properties_.push_back(JSPropertyInfo());
ClassDef.Properties = s_properties_.data();
s_variables_ = std::move(Cdb.variables_);
s_variables_.push_back(JSPropertyInfo());
ClassDef.Variables = s_variables_.data();
s_constructorInfos_ = std::move(Cdb.constructorInfos_);
s_constructorInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.ConstructorInfos = s_constructorInfos_.data();
s_methodInfos_ = std::move(Cdb.methodInfos_);
s_methodInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.MethodInfos = s_methodInfos_.data();
s_functionInfos_ = std::move(Cdb.functionInfos_);
s_functionInfos_.push_back(NamedFunctionInfo{nullptr, nullptr});
ClassDef.FunctionInfos = s_functionInfos_.data();
s_propertyInfos_ = std::move(Cdb.propertyInfos_);
s_propertyInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
ClassDef.PropertyInfos = s_propertyInfos_.data();
s_variableInfos_ = std::move(Cdb.variableInfos_);
s_variableInfos_.push_back(NamedPropertyInfo{nullptr, nullptr});
ClassDef.VariableInfos = s_variableInfos_.data();
RegisterJSClass(ClassDef);
}
template <typename T>
using Converter = Converter<T>;
template <typename T>
using CustomArgumentBufferType = CustomArgumentBufferType<T>;
};
class StringHolder
{
public:
StringHolder(v8::Local<v8::Context> context, const v8::Local<v8::Value> value)
{
needFree = false;
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
}
else if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
data = static_cast<char*>(DataTransfer::GetArrayBufferData(Ab));
}
else
{
if (value.IsEmpty())
return;
const auto isolate = context->GetIsolate();
v8::TryCatch try_catch(isolate);
v8::Local<v8::String> str;
if (!value->ToString(context).ToLocal(&str))
return;
const int length = str->Utf8Length(isolate);
data = new char[length + 1];
str->WriteUtf8(isolate, data);
needFree = true;
}
}
~StringHolder()
{
if (needFree && data)
{
delete[] data;
}
}
const char* Data() const
{
return data;
}
// Disallow copying and assigning.
StringHolder(const StringHolder&) = delete;
void operator=(const StringHolder&) = delete;
private:
char* data;
bool needFree;
};
template <>
struct CustomArgumentBufferType<const char*>
{
using type = StringHolder;
static constexpr bool enable = true;
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::BigInt::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Int64Value()) : 0;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) == 8 && !std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::BigInt::NewFromUnsigned(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt() ? static_cast<T>(value->ToBigInt(context).ToLocalChecked()->Uint64Value()) : 0;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBigInt();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Int32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsInt32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8 && !std::is_signed<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::NewFromUnsigned(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Uint32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsUint32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Integer::New(context->GetIsolate(), static_cast<int>(value));
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->Int32Value(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsInt32();
}
};
template <typename T>
struct Converter<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return v8::Number::New(context->GetIsolate(), value);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return static_cast<T>(value->NumberValue(context).ToChecked());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsNumber();
}
};
template <>
struct Converter<std::string>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, std::string value)
{
return v8::String::NewFromUtf8(context->GetIsolate(), value.c_str(), v8::NewStringType::kNormal).ToLocalChecked();
}
static std::string toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return *v8::String::Utf8Value(context->GetIsolate(), value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<const char*>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const char* value)
{
return v8::String::NewFromUtf8(context->GetIsolate(), value, v8::NewStringType::kNormal).ToLocalChecked();
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsString();
}
};
template <>
struct Converter<void*>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, void* value)
{
return DataTransfer::NewArrayBuffer(context, value, 0);
}
static void* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
return static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset();
}
if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
return DataTransfer::GetArrayBufferData(Ab);
}
if (value->IsObject())
{
return DataTransfer::GetPointerFast<void>(value.As<v8::Object>());
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <>
struct Converter<bool>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, bool value)
{
return v8::Boolean::New(context->GetIsolate(), value);
}
static bool toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->BooleanValue(context->GetIsolate());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsBoolean();
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<!is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
{
auto result = v8::Object::New(context->GetIsolate());
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
return result;
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsObject())
{
auto outer = value->ToObject(context).ToLocalChecked();
auto realvalue = outer->Get(context, 0).ToLocalChecked();
return Converter<T>::toCpp(context, realvalue);
}
return {};
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject(); // do not checked inner
}
};
template <typename T>
struct Converter<std::reference_wrapper<T>, typename std::enable_if<is_objecttype<T>::value || is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T& value)
{
auto result = v8::Object::New(context->GetIsolate());
auto _unused = result->Set(context, 0, Converter<T>::toScript(context, value));
return result;
}
static T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (!value.IsEmpty() && value->IsObject())
{
auto outer = value->ToObject(context).ToLocalChecked();
auto realvalue = outer->Get(context, 0).ToLocalChecked();
return Converter<typename std::decay<T>::type*>::toCpp(context, realvalue);
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject(); // do not checked inner
}
};
template <typename T>
struct Converter<T,
typename std::enable_if<is_script_type<typename std::remove_pointer<T>::type>::value && !std::is_array<T>::value &&
!std::is_const<typename std::remove_pointer<T>::type>::value && std::is_pointer<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return DataTransfer::NewArrayBuffer(context, value, 0);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> BuffView = value.As<v8::ArrayBufferView>();
auto Ab = BuffView->Buffer();
return reinterpret_cast<T>(static_cast<char*>(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset());
}
if (value->IsArrayBuffer())
{
auto Ab = v8::Local<v8::ArrayBuffer>::Cast(value);
return static_cast<T>(DataTransfer::GetArrayBufferData(Ab));
}
return nullptr;
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsArrayBuffer() || value->IsArrayBufferView();
}
};
template <typename T, std::size_t Size>
struct Converter<T[Size], typename std::enable_if<is_script_type<T>::value && !std::is_const<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value[Size])
{
return DataTransfer::NewArrayBuffer(context, &(value[0]), sizeof(T) * Size);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
if (value->IsArrayBufferView())
{
v8::Local<v8::ArrayBufferView> buffView = value.As<v8::ArrayBufferView>();
return buffView->ByteLength() >= sizeof(T) * Size;
}
if (value->IsArrayBuffer())
{
auto ab = v8::Local<v8::ArrayBuffer>::Cast(value);
size_t byteLength;
(void) (DataTransfer::GetArrayBufferData(ab, byteLength));
return byteLength >= sizeof(T) * Size;
}
return false;
}
};
template <class T>
struct Converter<T, typename std::enable_if<std::is_copy_constructible<T>::value && std::is_constructible<T>::value &&
is_objecttype<T>::value && !is_uetype<T>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, T value)
{
return DataTransfer::FindOrAddCData(context->GetIsolate(), context, DynamicTypeId<T>::get(&value), new T(value), false);
}
static T toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
T* ptr = DataTransfer::GetPointerFast<T>(value.As<v8::Object>());
return ptr ? *ptr : T{};
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return DataTransfer::IsInstanceOf(context->GetIsolate(), StaticTypeId<T>::get(), value.As<v8::Object>());
}
};
template <class T>
struct Converter<const T*,
typename std::enable_if<(is_objecttype<T>::value || std::is_same<T, void>::value || is_script_type<T>::value) &&
!is_uetype<T>::value && !std::is_same<T, char>::value>::type>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, const T* value)
{
return Converter<T*>::toScript(context, const_cast<T*>(value));
}
static const T* toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Converter<T*>::toCpp(context, value);
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Converter<T*>::accept(context, value);
}
};
} // namespace v8_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,215 @@
/*
* 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.
*/
#pragma once
#pragma warning(push, 0)
#include <v8-fast-api-calls.h>
#pragma warning(pop)
#include "DataTransfer.h"
namespace PUERTS_NAMESPACE
{
template <typename T, typename Enable = void>
struct FastCallArgument
{
};
template <typename T>
struct FastCallArgument<T, typename std::enable_if<std::is_pointer<T>::value && !std::is_same<T, const char*>::value &&
!std::is_enum<typename std::remove_pointer<T>::type>::value &&
!std::is_integral<typename std::remove_pointer<T>::type>::value &&
!std::is_floating_point<typename std::remove_pointer<T>::type>::value>::type>
{
using DeclType = v8::Local<v8::Value>;
static T Get(v8::Local<v8::Value> v)
{
if (V8_LIKELY(v->IsObject()))
{
// return static_cast<T>(v.As<v8::Object>()->GetAlignedPointerFromInternalField(1));
return static_cast<T>(DataTransfer::GetPointerFast<void>(v.As<v8::Object>()));
}
return nullptr;
}
};
template <>
struct FastCallArgument<std::string*>
{
};
template <typename T>
struct FastCallArgument<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
using DeclType = int;
static T Get(int i)
{
return static_cast<T>(i);
}
};
template <typename T>
struct FastCallArgument<T, typename std::enable_if<std::is_integral<T>::value || std::is_floating_point<T>::value>::type>
{
using DeclType = typename std::decay<T>::type;
static T Get(typename std::decay<T>::type i)
{
return i;
}
};
template <>
struct FastCallArgument<bool>
{
using DeclType = bool;
static bool Get(bool i)
{
return i;
}
};
namespace internal
{
namespace fastcallutil
{
template <bool _First_value, class _First, class... _Rest>
struct _Conjunction
{ // handle false trait or last trait
using type = _First;
};
template <class _True, class _Next, class... _Rest>
struct _Conjunction<true, _True, _Next, _Rest...>
{ // the first trait is true, try the next one
using type = typename _Conjunction<_Next::value, _Next, _Rest...>::type;
};
template <class... _Traits>
struct Conjunction : std::true_type
{
}; // If _Traits is empty, true_type
template <class _First, class... _Rest>
struct Conjunction<_First, _Rest...> : _Conjunction<_First::value, _First, _Rest...>::type
{
// the first false trait in _Traits, or the last trait if none are false
};
template <class...>
using Void_t = void;
} // namespace fastcallutil
} // namespace internal
template <typename T, typename = void>
struct IsArgSupportedHelper : std::false_type
{
};
template <typename T>
struct IsArgSupportedHelper<T, internal::fastcallutil::Void_t<decltype(&FastCallArgument<T>::Get)>> : std::true_type
{
};
template <typename T, typename = void>
struct IsArgsSupportedHelper : std::false_type
{
};
template <typename... Args>
struct IsArgsSupportedHelper<std::tuple<Args...>,
typename std::enable_if<internal::fastcallutil::Conjunction<IsArgSupportedHelper<Args>...>::value>::type> : std::true_type
{
};
template <typename T, typename = void>
struct IsReturnSupportedHelper : std::false_type
{
};
template <typename T>
struct IsReturnSupportedHelper<T,
typename std::enable_if<IsArgSupportedHelper<T>::value && !std::is_pointer<T>::value && !std::is_integral<T>::value>::type>
: std::true_type
{
};
template <typename T>
struct IsReturnSupportedHelper<T, typename std::enable_if<std::is_integral<T>::value && sizeof(T) < 8>::type> : std::true_type
{
};
template <>
struct IsReturnSupportedHelper<void> : std::true_type
{
};
template <typename T, T, typename Enable = void>
struct V8FastCall
{
static const v8::CFunction* info()
{
return nullptr;
}
};
template <typename Ret, typename... Args, Ret (*func)(Args...)>
struct V8FastCall<Ret (*)(Args...), func,
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value &&
(sizeof...(Args) > 0)>::type>
{
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
{
return func(FastCallArgument<Args>::Get(args)...);
}
static const v8::CFunction* info()
{
static v8::CFunction _info = v8::CFunction::Make(Wrap);
return &_info;
}
};
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...)>
struct V8FastCall<Ret (Inc::*)(Args...), func,
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value>::type>
{
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
{
auto self = FastCallArgument<Inc*>::Get(receiver_obj);
return (self->*func)(FastCallArgument<Args>::Get(args)...);
}
static const v8::CFunction* info()
{
static v8::CFunction _info = v8::CFunction::Make(Wrap);
return &_info;
}
};
template <typename Inc, typename Ret, typename... Args, Ret (Inc::*func)(Args...) const>
struct V8FastCall<Ret (Inc::*)(Args...) const, func,
typename std::enable_if<IsReturnSupportedHelper<Ret>::value && IsArgsSupportedHelper<std::tuple<Args...>>::value>::type>
{
static Ret Wrap(v8::Local<v8::Object> receiver_obj, typename FastCallArgument<Args>::DeclType... args)
{
auto self = FastCallArgument<Inc*>::Get(receiver_obj);
return (self->*func)(FastCallArgument<Args>::Get(args)...);
}
static const v8::CFunction* info()
{
static v8::CFunction _info = v8::CFunction::Make(Wrap);
return &_info;
}
};
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,379 @@
/*
* 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.
*/
#pragma once
#include "Binding.hpp"
#include <memory>
#ifdef USING_IN_UNREAL_ENGINE
#include "JSLogger.h"
#include "V8Utils.h"
#else
#include <iostream>
#endif
namespace PUERTS_NAMESPACE
{
namespace v8_impl
{
static inline void REPORT_EXCEPTION(v8::Isolate* Isolate, v8::TryCatch* TC)
{
#ifdef USING_IN_UNREAL_ENGINE
UE_LOG(Puerts, Error, TEXT("call function throw: %s"), *FV8Utils::TryCatchToString(Isolate, TC));
#else
std::cout << "call function throw: " << *v8::String::Utf8Value(Isolate, TC->Exception()) << std::endl;
#endif
}
class Object
{
public:
Object()
{
}
Object(v8::Local<v8::Context> context, v8::Local<v8::Value> object)
{
Isolate = context->GetIsolate();
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
GContext.Reset(Isolate, context);
GObject.Reset(Isolate, object.As<v8::Object>());
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
}
Object(const Object& InOther)
{
if (InOther.JsEnvLifeCycleTracker.expired())
{
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
return;
}
Isolate = InOther.Isolate;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
}
Object& operator=(const Object& InOther)
{
if (InOther.JsEnvLifeCycleTracker.expired())
{
JsEnvLifeCycleTracker = InOther.JsEnvLifeCycleTracker;
return *this;
}
Isolate = InOther.Isolate;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
GContext.Reset(Isolate, InOther.GContext.Get(Isolate));
GObject.Reset(Isolate, InOther.GObject.Get(Isolate));
JsEnvLifeCycleTracker = DataTransfer::GetJsEnvLifeCycleTracker(Isolate);
return *this;
}
~Object()
{
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
if (JsEnvLifeCycleTracker.expired())
{
#if V8_MAJOR_VERSION < 11
GObject.Empty();
GContext.Empty();
#endif
}
else
{
GObject.Reset();
GContext.Reset();
}
}
template <typename T>
T Get(const char* key) const
{
if (JsEnvLifeCycleTracker.expired())
{
return {};
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
auto MaybeValue = Object->Get(Context, v8_impl::Converter<const char*>::toScript(Context, key));
v8::Local<v8::Value> Val;
if (MaybeValue.ToLocal(&Val))
{
return v8_impl::Converter<T>::toCpp(Context, Val);
}
return {};
}
template <typename T>
void Set(const char* key, T val) const
{
if (JsEnvLifeCycleTracker.expired())
{
return;
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
auto _UnUsed = Object->Set(
Context, v8_impl::Converter<const char*>::toScript(Context, key), v8_impl::Converter<T>::toScript(Context, val));
}
bool IsValid() const
{
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
return false;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
return !Object.IsEmpty() && Object->IsObject();
}
// for performance considerations, a native can only hold one JavaScript object at a time (the last setting takes effect if set
// multiple times). If there is a need to hold more than one JavaScript object, it is recommended to first hold a JavaScript
// array and then add objects to the array.
template <typename T>
void SetWeakAndOwnBy(const T* Owner)
{
if (!Owner)
return;
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
return;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Val = DataTransfer::FindOrAddCData(Isolate, Context, StaticTypeId<T>::get(), Owner, true);
if (Val->IsObject())
{
auto JsObject = Val.template As<v8::Object>();
#if V8_MAJOR_VERSION < 8
JsObject->Set(Context, v8::String::NewFromUtf8(Isolate, "_p_i_only_one_child").ToLocalChecked(), GObject.Get(Isolate))
.Check();
#else
JsObject->Set(Context, v8::String::NewFromUtf8Literal(Isolate, "_p_i_only_one_child"), GObject.Get(Isolate)).Check();
#endif
GObject.SetWeak();
}
}
v8::Isolate* Isolate;
#if V8_MAJOR_VERSION >= 11
v8::Persistent<v8::Context> GContext;
v8::Persistent<v8::Object> GObject;
#else
v8::Global<v8::Context> GContext;
v8::Global<v8::Object> GObject;
#endif
std::weak_ptr<int> JsEnvLifeCycleTracker;
friend struct PUERTS_NAMESPACE::v8_impl::Converter<Object>;
};
class Function : public Object
{
public:
Function()
{
}
Function(v8::Local<v8::Context> context, v8::Local<v8::Value> object) : Object(context, object)
{
}
template <typename... Args>
void Action(Args... cppArgs) const
{
if (JsEnvLifeCycleTracker.expired())
{
return;
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
v8::TryCatch TryCatch(Isolate);
auto _UnUsed = InvokeHelper(Context, Object, cppArgs...);
if (TryCatch.HasCaught())
{
REPORT_EXCEPTION(Isolate, &TryCatch);
}
}
template <typename Ret, typename... Args>
Ret Func(Args... cppArgs) const
{
if (JsEnvLifeCycleTracker.expired())
{
return {};
}
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
v8::TryCatch TryCatch(Isolate);
auto MaybeRet = InvokeHelper(Context, Object, cppArgs...);
if (TryCatch.HasCaught())
{
REPORT_EXCEPTION(Isolate, &TryCatch);
}
if (!MaybeRet.IsEmpty())
{
return v8_impl::Converter<Ret>::toCpp(Context, MaybeRet.ToLocalChecked());
}
return {};
}
bool IsValid() const
{
if (JsEnvLifeCycleTracker.expired() || !Isolate || GContext.IsEmpty() || GObject.IsEmpty())
return false;
#ifdef THREAD_SAFE
v8::Locker Locker(Isolate);
#endif
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
auto Context = GContext.Get(Isolate);
v8::Context::Scope ContextScope(Context);
auto Object = GObject.Get(Isolate);
return !Object.IsEmpty() && Object->IsFunction();
}
private:
template <typename... Args>
auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object, Args... CppArgs) const
{
v8::Local<v8::Value> Argv[sizeof...(Args)]{v8_impl::Converter<Args>::toScript(Context, CppArgs)...};
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), sizeof...(Args), Argv);
}
auto InvokeHelper(v8::Local<v8::Context>& Context, v8::Local<v8::Object>& Object) const
{
return Object.As<v8::Function>()->Call(Context, v8::Undefined(Isolate), 0, nullptr);
}
friend struct PUERTS_NAMESPACE::v8_impl::Converter<Function>;
};
} // namespace v8_impl
template <>
struct ScriptTypeName<v8_impl::Object>
{
static constexpr auto value()
{
return internal::Literal("object");
}
};
template <>
struct ScriptTypeName<v8_impl::Function>
{
static constexpr auto value()
{
return internal::Literal("()=>void");
}
};
namespace v8_impl
{
template <>
struct Converter<Object>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, Object value)
{
return value.GObject.Get(context->GetIsolate());
}
static Object toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Object(context, value.As<v8::Object>());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsObject();
}
};
template <>
struct Converter<Function>
{
static v8::Local<v8::Value> toScript(v8::Local<v8::Context> context, Function value)
{
return value.GObject.Get(context->GetIsolate());
}
static Function toCpp(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return Function(context, value.As<v8::Object>());
}
static bool accept(v8::Local<v8::Context> context, const v8::Local<v8::Value>& value)
{
return value->IsFunction();
}
};
#include "StdFunctionConverter.hpp"
} // namespace v8_impl
} // namespace PUERTS_NAMESPACE
@@ -0,0 +1,320 @@
/*
* 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.
*/
#pragma once
#include <vector>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "NamespaceDef.h"
#include "DataTransfer.h"
#include "UECompatible.h"
namespace PUERTS_NAMESPACE
{
enum ArgType
{
EArgInt32,
EArgNumber,
EArgString,
EArgExternal,
EArgFunction,
EArgObject
};
class JSENV_API FV8Utils
{
public:
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const FString& Message)
{
ThrowException(Isolate, TCHAR_TO_ANSI(*Message));
}
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const char* Message)
{
auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked();
Isolate->ThrowException(v8::Exception::Error(ExceptionStr));
}
FORCEINLINE static void* GetPointer(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
{
if (Value.IsEmpty() || !Value->IsObject() || Value->IsUndefined() || Value->IsNull())
{
return nullptr;
}
auto Object = Value->ToObject(Context).ToLocalChecked();
return GetPointerFast<void>(Object, Index);
}
FORCEINLINE static void* GetPointer(v8::Local<v8::Object> Object, int Index = 0)
{
if (Object.IsEmpty() || Object->IsUndefined() || Object->IsNull())
{
return nullptr;
}
return GetPointerFast<void>(Object, Index);
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index = 0)
{
return DataTransfer::GetPointerFast<T>(Object, Index);
}
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
{
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Context, Value, Index));
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
? UEObject
: RELEASED_UOBJECT;
}
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Object> Object, int Index = 0)
{
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Object, Index));
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
? UEObject
: RELEASED_UOBJECT;
}
FORCEINLINE static bool IsReleasedPtr(void* Ptr)
{
return RELEASED_UOBJECT_MEMBER == Ptr;
}
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const FString& String)
{
return ToV8String(Isolate, String);
}
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const char* String)
{
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
}
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
FORCEINLINE static FName ToFName(v8::Isolate* Isolate, v8::Local<v8::Value> Value)
{
return UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Value)));
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FString& String)
{
// return ToV8String(Isolate, TCHAR_TO_UTF8(*String));
return ToV8String(Isolate, *String);
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FName& String)
{
const FNameEntry* Entry = String.GetComparisonNameEntry();
FString Out;
if (String.GetNumber() == NAME_NO_NUMBER_INTERNAL)
{
Out.Empty(Entry->GetNameLength());
Entry->AppendNameToString(Out);
}
else
{
Out.Empty(Entry->GetNameLength() + 6);
Entry->AppendNameToString(Out);
Out += TEXT('_');
Out.AppendInt(NAME_INTERNAL_TO_EXTERNAL(String.GetNumber()));
}
return ToV8String(Isolate, Out);
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FText& String)
{
return ToV8String(Isolate, String.ToString());
}
static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const TCHAR* String);
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const char* String)
{
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
}
static v8::Local<v8::String> ToV8StringFromFileContent(v8::Isolate* Isolate, const TArray<uint8>& FileContent)
{
const uint8* Buffer = FileContent.GetData();
auto Size = FileContent.Num();
if (Size >= 2 && !(Size & 1) && ((Buffer[0] == 0xff && Buffer[1] == 0xfe) || (Buffer[0] == 0xfe && Buffer[1] == 0xff)))
{
FString Content;
FFileHelper::BufferToString(Content, Buffer, Size);
return ToV8String(Isolate, Content);
}
else
{
if (Size >= 3 && Buffer[0] == 0xef && Buffer[1] == 0xbb && Buffer[2] == 0xbf)
{
// Skip over UTF-8 BOM if there is one
Buffer += 3;
Size -= 3;
}
return v8::String::NewFromUtf8(Isolate, (const char*) Buffer, v8::NewStringType::kNormal, Size).ToLocalChecked();
}
}
template <typename T>
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
{
return DataTransfer::IsolateData<T>(Isolate);
}
FORCEINLINE static bool CheckArgumentLength(const v8::FunctionCallbackInfo<v8::Value>& Info, int32 Length)
{
if (Info.Length() < Length)
{
ThrowException(Info.GetIsolate(),
FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."), Length, Info.Length()));
return false;
}
return true;
}
FORCEINLINE static FString TryCatchToString(v8::Isolate* Isolate, v8::TryCatch* TryCatch)
{
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::String::Utf8Value Exception(Isolate, TryCatch->Exception());
FString ExceptionStr(UTF8_TO_TCHAR(*Exception));
v8::Local<v8::Message> Message = TryCatch->Message();
if (Message.IsEmpty())
{
// 如果没有提供更详细的信息,直接输出Exception
return ExceptionStr;
}
else
{
v8::Local<v8::Context> Context(Isolate->GetCurrentContext());
// 输出 (filename):(line number): (message).
v8::String::Utf8Value FileName(Isolate, Message->GetScriptResourceName());
int LineNum = Message->GetLineNumber(Context).FromJust();
FString FileNameStr(*FileName);
FString LineNumStr = FString::FromInt(LineNum);
FString FileInfoStr;
FileInfoStr.Append(FileNameStr).Append(":").Append(LineNumStr).Append(": ").Append(ExceptionStr);
FString FinalReport;
FinalReport.Append(FileInfoStr).Append("\n");
// 输出调用栈信息
v8::Local<v8::Value> StackTrace;
if (TryCatch->StackTrace(Context).ToLocal(&StackTrace))
{
v8::String::Utf8Value StackTraceVal(Isolate, StackTrace);
FString StackTraceStr(*StackTraceVal);
FinalReport.Append("\n").Append(StackTraceStr);
}
return FinalReport;
}
}
FORCEINLINE static bool CheckArgument(const v8::FunctionCallbackInfo<v8::Value>& Info, const std::vector<ArgType>& TypesExpect)
{
if (Info.Length() < TypesExpect.size())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."),
TypesExpect.size(), Info.Length()));
return false;
}
for (int i = 0; i < TypesExpect.size(); ++i)
{
switch (TypesExpect[i])
{
case EArgInt32:
if (!Info[i]->IsInt32())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
return false;
}
else
{
break;
}
case EArgNumber:
if (!Info[i]->IsNumber())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
return false;
}
else
{
break;
}
case EArgString:
if (!Info[i]->IsString())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a string."), i));
return false;
}
else
{
break;
}
case EArgExternal:
if (!Info[i]->IsExternal())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect an external."), i));
return false;
}
else
{
break;
}
case EArgFunction:
if (!Info[i]->IsFunction())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a function."), i));
return false;
}
else
{
break;
}
case EArgObject:
if (!Info[i]->IsObject())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a object."), i));
return false;
}
else
{
break;
}
default:
break;
}
}
return true;
}
};
} // namespace PUERTS_NAMESPACE
#define CHECK_V8_ARGS_LEN(Length) \
if (!FV8Utils::CheckArgumentLength(Info, Length)) \
{ \
return; \
}
#define CHECK_V8_ARGS(...) \
static std::vector<ArgType> ArgExpect = {__VA_ARGS__}; \
if (!FV8Utils::CheckArgument(Info, ArgExpect)) \
{ \
return; \
}
+277
View File
@@ -0,0 +1,277 @@
/*
* 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.
*/
#ifndef PS_API_H_
#define PS_API_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
// Portable Embedded Scripting API
#define PESAPI_VERSION 11
#define PESAPI_EXTERN
#if defined(__APPLE__) && defined(BUILDING_PES_EXTENSION) && !defined(PESAPI_ADPT_C)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
#define USING_OBJC_REFLECTION
#endif
#endif
#ifdef USING_OBJC_REFLECTION
#import <Foundation/Foundation.h>
#endif
#ifdef _WIN32
#define PESAPI_MODULE_EXPORT __declspec(dllexport)
#else
#define PESAPI_MODULE_EXPORT __attribute__((visibility("default")))
#endif
#if defined(__GNUC__)
#define PESAPI_NO_RETURN __attribute__((noreturn))
#elif defined(_WIN32)
#define PESAPI_NO_RETURN __declspec(noreturn)
#else
#define PESAPI_NO_RETURN
#endif
#ifdef __cplusplus
#define EXTERN_C_START \
extern "C" \
{
#define EXTERN_C_END }
#else
#define EXTERN_C_START
#define EXTERN_C_END
#endif
#define PESAPI_MODULE_INITIALIZER_X(base, module, version) PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version)
#define PESAPI_MODULE_INITIALIZER_X_HELPER(base, module, version) base##module##_v##version
#define PESAPI_MODULE_INITIALIZER_BASE pesapi_register_
#define PESAPI_MODULE_INITIALIZER(modname) PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, modname, PESAPI_VERSION)
#define PESAPI_MODULE_VERSION() PESAPI_MODULE_INITIALIZER_X(PESAPI_MODULE_INITIALIZER_BASE, version, 0)
#ifdef USING_OBJC_REFLECTION
#define PESAPI_MODULE(modname, initfunc) \
@interface PESAPI_MODULE_INITIALIZER (modname) : NSObject \
@end \
@implementation PESAPI_MODULE_INITIALIZER (modname) \
+(void) initlib : (pesapi_func_ptr*) func_ptr_array \
{ \
pesapi_init(func_ptr_array); \
initfunc(); \
} \
@end
#else
#define PESAPI_MODULE(modname, initfunc) \
EXTERN_C_START \
PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array); \
PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array); \
PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()(); \
EXTERN_C_END \
PESAPI_MODULE_EXPORT void PESAPI_MODULE_INITIALIZER(modname)(pesapi_func_ptr * func_ptr_array) \
{ \
pesapi_init(func_ptr_array); \
initfunc(); \
} \
PESAPI_MODULE_EXPORT const char* PESAPI_MODULE_INITIALIZER(dynamic)(pesapi_func_ptr * func_ptr_array) \
{ \
if (func_ptr_array) \
{ \
pesapi_init(func_ptr_array); \
initfunc(); \
} \
return #modname; \
} \
PESAPI_MODULE_EXPORT int PESAPI_MODULE_VERSION()() \
{ \
return PESAPI_VERSION; \
}
#endif
EXTERN_C_START
// alloc on stack
struct pesapi_scope_memory
{
int padding__[32];
};
typedef struct pesapi_env__* pesapi_env;
typedef struct pesapi_env_ref__* pesapi_env_ref;
typedef struct pesapi_value__* pesapi_value;
typedef struct pesapi_value_ref__* pesapi_value_ref;
typedef struct pesapi_callback_info__* pesapi_callback_info;
typedef struct pesapi_scope__* pesapi_scope;
typedef struct pesapi_type_info__* pesapi_type_info;
typedef struct pesapi_signature_info__* pesapi_signature_info;
typedef struct pesapi_property_descriptor__* pesapi_property_descriptor;
typedef void (*pesapi_callback)(pesapi_callback_info info);
typedef void* (*pesapi_constructor)(pesapi_callback_info info);
typedef void (*pesapi_finalize)(void* ptr, void* class_data, void* env_private);
typedef void* (*pesapi_on_native_object_enter)(void* ptr, void* class_data, void* env_private);
// userdata: return of pesapi_on_native_object_enter
typedef void (*pesapi_on_native_object_exit)(void* ptr, void* class_data, void* env_private, void* userdata);
typedef bool (*pesapi_class_not_found_callback)(const void* type_id);
typedef void (*pesapi_func_ptr)(void);
#ifdef BUILDING_PES_EXTENSION
PESAPI_EXTERN void pesapi_init(pesapi_func_ptr* func_array);
#else
PESAPI_MODULE_EXPORT int pesapi_load_addon(const char* path, const char* module_name);
#endif
// value process
PESAPI_EXTERN pesapi_value pesapi_create_null(pesapi_env env);
PESAPI_EXTERN pesapi_value pesapi_create_undefined(pesapi_env env);
PESAPI_EXTERN pesapi_value pesapi_create_boolean(pesapi_env env, bool value);
PESAPI_EXTERN pesapi_value pesapi_create_int32(pesapi_env env, int32_t value);
PESAPI_EXTERN pesapi_value pesapi_create_uint32(pesapi_env env, uint32_t value);
PESAPI_EXTERN pesapi_value pesapi_create_int64(pesapi_env env, int64_t value);
PESAPI_EXTERN pesapi_value pesapi_create_uint64(pesapi_env env, uint64_t value);
PESAPI_EXTERN pesapi_value pesapi_create_double(pesapi_env env, double value);
PESAPI_EXTERN pesapi_value pesapi_create_string_utf8(pesapi_env env, const char* str, size_t length);
PESAPI_EXTERN pesapi_value pesapi_create_binary(pesapi_env env, void* str, size_t length);
PESAPI_EXTERN pesapi_value pesapi_create_array(pesapi_env env);
PESAPI_EXTERN pesapi_value pesapi_create_object(pesapi_env env);
PESAPI_EXTERN pesapi_value pesapi_create_function(pesapi_env env, pesapi_callback native_impl, void* data);
PESAPI_EXTERN pesapi_value pesapi_create_class(pesapi_env env, const void* type_id);
PESAPI_EXTERN bool pesapi_get_value_bool(pesapi_env env, pesapi_value value);
PESAPI_EXTERN int32_t pesapi_get_value_int32(pesapi_env env, pesapi_value value);
PESAPI_EXTERN uint32_t pesapi_get_value_uint32(pesapi_env env, pesapi_value value);
PESAPI_EXTERN int64_t pesapi_get_value_int64(pesapi_env env, pesapi_value value);
PESAPI_EXTERN uint64_t pesapi_get_value_uint64(pesapi_env env, pesapi_value value);
PESAPI_EXTERN double pesapi_get_value_double(pesapi_env env, pesapi_value value);
PESAPI_EXTERN const char* pesapi_get_value_string_utf8(pesapi_env env, pesapi_value value, char* buf, size_t* bufsize);
PESAPI_EXTERN void* pesapi_get_value_binary(pesapi_env env, pesapi_value pvalue, size_t* bufsize);
PESAPI_EXTERN uint32_t pesapi_get_array_length(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_null(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_undefined(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_boolean(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_int32(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_uint32(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_int64(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_uint64(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_double(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_string(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_object(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_function(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_binary(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_array(pesapi_env env, pesapi_value value);
PESAPI_EXTERN pesapi_value pesapi_native_object_to_value(pesapi_env env, const void* type_id, void* object_ptr, bool call_finalize);
PESAPI_EXTERN void* pesapi_get_native_object_ptr(pesapi_env env, pesapi_value value);
PESAPI_EXTERN const void* pesapi_get_native_object_typeid(pesapi_env env, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_instance_of(pesapi_env env, const void* type_id, pesapi_value value);
PESAPI_EXTERN pesapi_value pesapi_boxing(pesapi_env env, pesapi_value value);
PESAPI_EXTERN pesapi_value pesapi_unboxing(pesapi_env env, pesapi_value value);
PESAPI_EXTERN void pesapi_update_boxed_value(pesapi_env env, pesapi_value boxed_value, pesapi_value value);
PESAPI_EXTERN bool pesapi_is_boxed_value(pesapi_env env, pesapi_value value);
PESAPI_EXTERN int pesapi_get_args_len(pesapi_callback_info info);
PESAPI_EXTERN pesapi_value pesapi_get_arg(pesapi_callback_info info, int index);
PESAPI_EXTERN pesapi_env pesapi_get_env(pesapi_callback_info info);
PESAPI_EXTERN pesapi_value pesapi_get_this(pesapi_callback_info info);
PESAPI_EXTERN pesapi_value pesapi_get_holder(pesapi_callback_info info);
PESAPI_EXTERN void* pesapi_get_userdata(pesapi_callback_info info);
PESAPI_EXTERN void pesapi_add_return(pesapi_callback_info info, pesapi_value value);
PESAPI_EXTERN void pesapi_throw_by_string(pesapi_callback_info pinfo, const char* msg);
PESAPI_EXTERN pesapi_env_ref pesapi_create_env_ref(pesapi_env env);
PESAPI_EXTERN bool pesapi_env_ref_is_valid(pesapi_env_ref env);
PESAPI_EXTERN pesapi_env pesapi_get_env_from_ref(pesapi_env_ref env_ref);
PESAPI_EXTERN pesapi_env_ref pesapi_duplicate_env_ref(pesapi_env_ref env_ref);
PESAPI_EXTERN void pesapi_release_env_ref(pesapi_env_ref env_ref);
PESAPI_EXTERN pesapi_scope pesapi_open_scope(pesapi_env_ref env_ref);
PESAPI_EXTERN pesapi_scope pesapi_open_scope_placement(pesapi_env_ref env_ref, struct pesapi_scope_memory* memory);
PESAPI_EXTERN bool pesapi_has_caught(pesapi_scope scope);
PESAPI_EXTERN const char* pesapi_get_exception_as_string(pesapi_scope scope, bool with_stack);
PESAPI_EXTERN void pesapi_close_scope(pesapi_scope scope);
PESAPI_EXTERN void pesapi_close_scope_placement(pesapi_scope scope);
PESAPI_EXTERN pesapi_value_ref pesapi_create_value_ref(pesapi_env env, pesapi_value value, uint32_t internal_field_count);
PESAPI_EXTERN pesapi_value_ref pesapi_duplicate_value_ref(pesapi_value_ref value_ref);
PESAPI_EXTERN void pesapi_release_value_ref(pesapi_value_ref value_ref);
PESAPI_EXTERN pesapi_value pesapi_get_value_from_ref(pesapi_env env, pesapi_value_ref value_ref);
PESAPI_EXTERN void pesapi_set_ref_weak(pesapi_env env, pesapi_value_ref value_ref);
// Optional api: return false if can not fulfill
PESAPI_EXTERN bool pesapi_set_owner(pesapi_env env, pesapi_value value, pesapi_value owner);
// suggestion: struct pesapi_value_ref : pesapi_env_ref {...};
PESAPI_EXTERN pesapi_env_ref pesapi_get_ref_associated_env(pesapi_value_ref value_ref);
PESAPI_EXTERN void** pesapi_get_ref_internal_fields(pesapi_value_ref value_ref, uint32_t* pinternal_field_count);
PESAPI_EXTERN pesapi_value pesapi_get_property(pesapi_env env, pesapi_value object, const char* key);
PESAPI_EXTERN void pesapi_set_property(pesapi_env env, pesapi_value object, const char* key, pesapi_value value);
PESAPI_EXTERN bool pesapi_get_private(pesapi_env env, pesapi_value object, void** out_ptr);
PESAPI_EXTERN bool pesapi_set_private(pesapi_env env, pesapi_value object, void* ptr);
PESAPI_EXTERN pesapi_value pesapi_get_property_uint32(pesapi_env env, pesapi_value object, uint32_t key);
PESAPI_EXTERN void pesapi_set_property_uint32(pesapi_env env, pesapi_value object, uint32_t key, pesapi_value value);
PESAPI_EXTERN pesapi_value pesapi_call_function(
pesapi_env env, pesapi_value func, pesapi_value this_object, int argc, const pesapi_value argv[]);
PESAPI_EXTERN pesapi_value pesapi_eval(pesapi_env env, const uint8_t* code, size_t code_size, const char* path);
PESAPI_EXTERN pesapi_value pesapi_global(pesapi_env env);
PESAPI_EXTERN const void* pesapi_get_env_private(pesapi_env env);
PESAPI_EXTERN void pesapi_set_env_private(pesapi_env env, const void* ptr);
PESAPI_EXTERN pesapi_type_info pesapi_alloc_type_infos(size_t count);
PESAPI_EXTERN void pesapi_set_type_info(
pesapi_type_info type_infos, size_t index, const char* name, bool is_pointer, bool is_const, bool is_ref, bool is_primitive);
PESAPI_EXTERN pesapi_signature_info pesapi_create_signature_info(
pesapi_type_info return_type, size_t parameter_count, pesapi_type_info parameter_types);
PESAPI_EXTERN pesapi_property_descriptor pesapi_alloc_property_descriptors(size_t count);
// using pesapi_get_userdata obtain userdata in callback
PESAPI_EXTERN void pesapi_set_method_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static,
pesapi_callback method, void* data, pesapi_signature_info signature_info);
PESAPI_EXTERN void pesapi_set_property_info(pesapi_property_descriptor properties, size_t index, const char* name, bool is_static,
pesapi_callback getter, pesapi_callback setter, void* getter_data, void* setter_data, pesapi_type_info type_info);
PESAPI_EXTERN void pesapi_define_class(const void* type_id, const void* super_type_id, const char* type_name,
pesapi_constructor constructor, pesapi_finalize finalize, size_t property_count, pesapi_property_descriptor properties,
void* data);
PESAPI_EXTERN void* pesapi_get_class_data(const void* type_id, bool force_load);
PESAPI_EXTERN bool pesapi_trace_native_object_lifecycle(
const void* type_id, pesapi_on_native_object_enter on_enter, pesapi_on_native_object_exit on_exit);
PESAPI_EXTERN void pesapi_on_class_not_found(pesapi_class_not_found_callback callback);
PESAPI_EXTERN void pesapi_class_type_info(const char* proto_magic_id, const void* type_id, const void* constructor_info,
const void* methods_info, const void* functions_info, const void* properties_info, const void* variables_info);
PESAPI_EXTERN const void* pesapi_find_type_id(const char* module_name, const char* type_name);
EXTERN_C_END
#endif