/* * 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 \ { \ static constexpr auto value() \ { \ return internal::Literal(#CLS).Sub<1>(); \ } \ }; \ } \ namespace PUERTS_NAMESPACE \ { \ template <> \ struct is_uetype : public std::true_type \ { \ }; \ } #define UsingTArrayWithName(CLS, CLSNAME) \ namespace PUERTS_NAMESPACE \ { \ template <> \ struct ScriptTypeName> \ { \ static constexpr auto value() \ { \ return internal::Literal(CLSNAME); \ } \ }; \ } \ __DefObjectType(TArray) __DefCDataPointerConverter(TArray) #define UsingCrossModuleCppType(CLS) \ namespace PUERTS_NAMESPACE \ { \ template <> \ struct StaticTypeId \ { \ 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>() \ .Method("Add", SelectFunction(int (TArray::*)(CLS const&), &TArray::Add)) \ .Method("Get", SelectFunction(CLS& (TArray::*) (int), &TArray::operator[])) \ .Method("GetRef", SelectFunction(CLS& (TArray::*) (int), &TArray::operator[])) \ .Method("Num", MakeFunction(&TArray::Num)) \ .Method("Contains", MakeFunction(&TArray::Contains)) \ .Method("FindIndex", SelectFunction(int (TArray::*)(CLS const&) const, &TArray::Find)) \ .Method( \ "RemoveAt", SelectFunction(void (TArray::*)(int, /* New param in 5.4*/ EAllowShrinking), &TArray::RemoveAt)) \ .Method("IsValidIndex", MakeFunction(&TArray::IsValidIndex)) \ .Method("Empty", MakeFunction(&TArray::Empty)) \ .Register() #else #define RegisterTArray(CLS) \ PUERTS_NAMESPACE::DefineClass>() \ .Method("Add", SelectFunction(int (TArray::*)(CLS const&), &TArray::Add)) \ .Method("Get", SelectFunction(CLS& (TArray::*) (int), &TArray::operator[])) \ .Method("GetRef", SelectFunction(CLS& (TArray::*) (int), &TArray::operator[])) \ .Method("Num", MakeFunction(&TArray::Num)) \ .Method("Contains", MakeFunction(&TArray::Contains)) \ .Method("FindIndex", SelectFunction(int (TArray::*)(CLS const&) const, &TArray::Find)) \ .Method("RemoveAt", SelectFunction(void (TArray::*)(int), &TArray::RemoveAt)) \ .Method("IsValidIndex", MakeFunction(&TArray::IsValidIndex)) \ .Method("Empty", MakeFunction(&TArray::Empty)) \ .Register() #endif #define UsingUStruct(CLS) UsingUClass(CLS) #define UsingContainer(CLS) __DefObjectType(CLS) __DefCDataPointerConverter(CLS) #define UsingTSharedPtr(ITEMCLS) __DefObjectType(TSharedPtr) __DefCDataPointerConverter(TSharedPtr) template struct TSharedPtrExtension { static bool Equals(const TSharedPtr Lhs, const TSharedPtr Rhs) { return Lhs == Rhs; } }; #define RegisterTSharedPtr(ITEMCLS) \ PUERTS_NAMESPACE::DefineClass>() \ .Method("Equals", MakeExtension(&TSharedPtrExtension::Equals)) \ .Register(); namespace PUERTS_NAMESPACE { namespace v8_impl { class TCharStringHolder { public: TCharStringHolder() { } TCharStringHolder(v8::Local context, const v8::Local value) { Str = FV8Utils::ToFString(context->GetIsolate(), value); } const TCHAR* Data() const { return *Str; } private: FString Str; }; template <> struct CustomArgumentBufferType { using type = TCharStringHolder; static constexpr bool enable = true; }; template <> struct Converter { static v8::Local toScript(v8::Local context, FString value) { return FV8Utils::ToV8String(context->GetIsolate(), value); } static FString toCpp(v8::Local context, const v8::Local& value) { return FV8Utils::ToFString(context->GetIsolate(), value); } static bool accept(v8::Local context, const v8::Local& value) { return value->IsString(); } }; template <> struct Converter { static v8::Local toScript(v8::Local context, FName value) { return FV8Utils::ToV8String(context->GetIsolate(), value.ToString()); } static FName toCpp(v8::Local context, const v8::Local& value) { if (value->IsArrayBuffer()) { auto Ab = v8::Local::Cast(value); size_t ByteLength; auto Data = DataTransfer::GetArrayBufferData(Ab, ByteLength); if (ByteLength == sizeof(FName)) { return *static_cast(Data); } } return FV8Utils::ToFName(context->GetIsolate(), value); } static bool accept(v8::Local context, const v8::Local& value) { return value->IsString(); } }; template <> struct Converter { static v8::Local toScript(v8::Local context, const TCHAR* value) { return FV8Utils::ToV8String(context->GetIsolate(), value); } static TCharStringHolder toCpp(v8::Local context, const v8::Local& value) { return TCharStringHolder(context, value); } static bool accept(v8::Local context, const v8::Local& value) { return value->IsString(); } }; #ifndef PUERTS_FTEXT_AS_OBJECT template <> struct Converter { static v8::Local toScript(v8::Local context, FText value) { return FV8Utils::ToV8String(context->GetIsolate(), value.ToString()); } static FText toCpp(v8::Local context, const v8::Local& value) { return FText::FromString(FV8Utils::ToFString(context->GetIsolate(), value)); } static bool accept(v8::Local context, const v8::Local& value) { return value->IsString(); } }; #endif template <> struct Converter { static v8::Local toScript(v8::Local context, FArrayBuffer value) { return DataTransfer::NewArrayBuffer(context, value.Data, value.Length); } static FArrayBuffer toCpp(v8::Local context, const v8::Local& value) { FArrayBuffer Ret = {nullptr, 0}; if (value->IsArrayBufferView()) { v8::Local BuffView = value.As(); auto Ab = BuffView->Buffer(); Ret.Data = static_cast(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset(); Ret.Length = BuffView->ByteLength(); } else if (value->IsArrayBuffer()) { auto Ab = v8::Local::Cast(value); size_t ByteLength; Ret.Data = static_cast(DataTransfer::GetArrayBufferData(Ab, ByteLength)); Ret.Length = ByteLength; } return Ret; } static bool accept(v8::Local context, const v8::Local& value) { return value->IsArrayBuffer() || value->IsArrayBufferView(); } }; template <> struct Converter { static v8::Local toScript(v8::Local context, FArrayBufferValue& value) { v8::Local Ab = v8::ArrayBuffer::New(context->GetIsolate(), value.Data.Num()); void* Buff = static_cast(DataTransfer::GetArrayBufferData(Ab)); ::memcpy(Buff, value.Data.GetData(), value.Data.Num()); return Ab; } static FArrayBufferValue toCpp(v8::Local context, const v8::Local& value) { FArrayBufferValue Ret; size_t Len = 0; void* Data = nullptr; if (value->IsArrayBufferView()) { v8::Local BuffView = value.As(); auto Ab = BuffView->Buffer(); Data = static_cast(DataTransfer::GetArrayBufferData(Ab)) + BuffView->ByteOffset(); Len = BuffView->ByteLength(); } else if (value->IsArrayBuffer()) { auto Ab = v8::Local::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 context, const v8::Local& value) { return value->IsArrayBuffer() || value->IsArrayBufferView(); } }; template struct Converter::value>::type> { static v8::Local toScript(v8::Local context, T* value) { using TypeWithoutConst = typename std::remove_const::type; return DataTransfer::FindOrAddObject(context->GetIsolate(), context, (TypeWithoutConst*) (value)); } static T* toCpp(v8::Local context, const v8::Local& value) { T* Ret = DataTransfer::GetPointerFast(value.As()); return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast() || UEObjectIsPendingKill(Ret)) ? nullptr : Ret; } static bool accept(v8::Local context, const v8::Local& value) { if (value.As()->IsNullOrUndefined()) return true; return DataTransfer::IsInstanceOf(context->GetIsolate(), T::StaticClass(), value.As()); } }; template struct Converter::value && std::is_convertible::value>::type> { static v8::Local toScript(v8::Local context, T* value) { return DataTransfer::FindOrAddObject(context->GetIsolate(), context, static_cast(value)); } static T* toCpp(v8::Local context, const v8::Local& value) { T* Ret = DataTransfer::GetPointerFast(value.As()); return (!Ret || Ret == RELEASED_UOBJECT_MEMBER || !Ret->IsValidLowLevelFast()) ? nullptr : Ret; } static bool accept(v8::Local context, const v8::Local& value) { return DataTransfer::IsInstanceOf(context->GetIsolate(), UObject::StaticClass(), value.As()); } }; } // namespace v8_impl template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("string"); } }; template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("string"); } }; template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("string"); } }; #ifndef PUERTS_FTEXT_AS_OBJECT template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("string"); } }; #endif template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("ArrayBuffer"); } }; template <> struct ScriptTypeName { static constexpr auto value() { return internal::Literal("ArrayBuffer"); } }; template struct ScriptTypeNameWithNamespace::type>::type>::value>::type> { static constexpr auto value() { return internal::Literal("cpp.") + ScriptTypeName::value(); } }; template struct ScriptTypeNameWithNamespace::type>::type>::value>::type> { static constexpr auto value() { return internal::Literal("UE.") + ScriptTypeName::value(); } }; template struct ScriptTypeName> { static constexpr auto value() { return internal::Literal("UE.TSharedPtr<") + ScriptTypeNameWithNamespace::value() + internal::Literal(">"); } }; template struct ScriptTypeName> { static constexpr auto value() { return internal::Literal("UE.TArray<") + ScriptTypeNameWithNamespace::value() + internal::Literal(">"); } }; template struct ScriptTypeName> { static constexpr auto value() { return internal::Literal("UE.TSet<") + ScriptTypeNameWithNamespace::value() + internal::Literal(">"); } }; template struct ScriptTypeName> { static constexpr auto value() { return internal::Literal("UE.TMap<") + ScriptTypeNameWithNamespace::value() + internal::Literal(", ") + ScriptTypeNameWithNamespace::value() + internal::Literal(">"); } }; namespace internal { template struct IsUStructHelper : std::false_type { }; template struct IsUStructHelper::Get)>> : std::true_type { }; } // namespace internal namespace v8_impl { template struct Converter::value && !std::is_convertible::value && internal::IsUStructHelper::value>::type> { static v8::Local toScript(v8::Local context, const T* value) { return DataTransfer::FindOrAddStruct(context->GetIsolate(), context, (void*) value, true); } static T* toCpp(v8::Local context, const v8::Local& value) { return DataTransfer::GetPointerFast(value.As()); } static bool accept(v8::Local context, const v8::Local& value) { return DataTransfer::IsInstanceOf(context->GetIsolate(), value.As()); } }; template struct Converter::value && internal::IsUStructHelper::value>::type> : Converter { }; template struct Converter::value>::type> { static v8::Local toScript(v8::Local context, const T value) { return DataTransfer::FindOrAddStruct(context->GetIsolate(), context, new T(value), false); } static T toCpp(v8::Local context, const v8::Local& value) { T* ptr = DataTransfer::GetPointerFast(value.As()); return ptr ? *ptr : T{}; } static bool accept(v8::Local context, const v8::Local& value) { return DataTransfer::IsInstanceOf(context->GetIsolate(), value.As()); } }; template struct Converter::value>::type> : Converter { }; } // namespace v8_impl template struct ScriptTypeName::value>::type> : ScriptTypeName { }; } // namespace PUERTS_NAMESPACE