diff --git a/unity/Assets/core/upm/Editor/Resources/puerts/templates/il2cpp_snippets.mjs b/unity/Assets/core/upm/Editor/Resources/puerts/templates/il2cpp_snippets.mjs new file mode 100644 index 0000000000..bda2ea9500 --- /dev/null +++ b/unity/Assets/core/upm/Editor/Resources/puerts/templates/il2cpp_snippets.mjs @@ -0,0 +1,351 @@ +/* +* 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. +*/ + +import { FOR, default as t, IF, ENDIF, ELSE } from "./tte.mjs" + +const sigs = CS.PuertsIl2cpp.TypeUtils.TypeSignatures; + +export function listToJsArray(csArr) { + let arr = []; + if (!csArr) return arr; + for (var i = 0; i < csArr.Count; i++) { + arr.push(csArr.get_Item(i)); + } + return arr; +} + +export const PrimitiveSignatureCppTypeMap = { + v: 'void', + b: 'bool', + u1: 'uint8_t', + i1: 'int8_t', + i2: 'int16_t', + u2: 'uint16_t', + i4: 'int32_t', + u4: 'uint32_t', + i8: 'int64_t', + u8: 'uint64_t', + c: 'Il2CppChar', + r8: 'double', + r4: 'float' +}; + +export function needThis(wrapperInfo) { + return wrapperInfo.ThisSignature == 't' || wrapperInfo.ThisSignature == 'T' +} + +export function getSignatureWithoutRefAndPrefix(signature) { + if (signature[0] == 'P' || signature[0] == 'D') { + return signature.substring(1); + } else { + return signature + } +} + +export function isStructOrNullableStruct(signature) { + return (signature.startsWith(sigs.StructPrefix) || signature.startsWith(sigs.NullableStructPrefix)) && signature.endsWith('_'); +} + +export function SToCPPType(signature) { + if (signature[0] == 'D') { + signature = signature.substring(1); + } + if (signature == 's') return 'Il2CppString*'; + if (signature == 'o' || signature == 'O' || signature == 'a') return 'Il2CppObject*'; + if (signature[0] == 'V') return 'Il2CppArray*'; + var t = (signature in PrimitiveSignatureCppTypeMap) ? PrimitiveSignatureCppTypeMap[signature] : "void*"; + if ((signature.startsWith(sigs.StructPrefix) || signature.startsWith(sigs.NullableStructPrefix)) && signature.endsWith('_')) { + t = `struct ${signature}`; + } + if (signature[0] == 'P') { + t = `${SToCPPType(signature.substring(1))}*` + } + return t; + } + +export function defineValueType(valueTypeInfo) { + // TODO 会存在一个 IsEnum 且 IsGenericParameter 的类型,signature为空,先过滤处理,晚点彻查。 + if (!valueTypeInfo.Signature) return '' + return t`// ${valueTypeInfo.CsName} +struct ${valueTypeInfo.Signature} +{ + ${FOR(listToJsArray(valueTypeInfo.FieldSignatures), (s, i) => t` + ${IF(valueTypeInfo.Signature.startsWith(sigs.NullableStructPrefix) && i == valueTypeInfo.NullableHasValuePosition)} + ${SToCPPType(s)} hasValue; + ${ELSE()} + ${SToCPPType(s)} p${i}; + ${ENDIF()} + `)} +}; + `; + } + +export function getThis(signature) { + let getJsThis = 'pesapi_value jsThis = pesapi_get_holder(info);' + if (signature == 't') { + return `${getJsThis} + auto self = pesapi_get_native_object_ptr(env, jsThis);` + } else if (signature == 'T') { + return `${getJsThis} + auto self = pesapi_get_native_object_ptr(env, jsThis); + auto ptrType = (Il2CppClass*) pesapi_get_native_object_typeid(env, jsThis); + if (Class::IsValuetype(ptrType)) + { + self = Object::Box(ptrType, self); + } +`; + } else { + return ''; + } +} + +export function getArgValue(signature, JSName, isRef) { + if (signature in PrimitiveSignatureCppTypeMap) { + return isRef ? `converter::Converter>::toCpp(env, ${JSName})` + : `converter::Converter<${PrimitiveSignatureCppTypeMap[signature]}>::toCpp(env, ${JSName})`; + + } else if ((signature == 'Pv' || signature == 'p') && !isRef) { + return `DataTransfer::GetPointer(env, ${JSName})`; + + } else { // default value + // TODO: object + if (signature in PrimitiveSignatureCppTypeMap) { + if (signature == 'v') throw "void has no default"; + return signature == 'b' ? 'false' : '0'; + } + + if ((signature.startsWith(sigs.StructPrefix) || signature.startsWith(sigs.NullableStructPrefix)) && signature.endsWith('_')) { + return '{}' + } + + return 'nullptr'; + } +} + +export function declareTypeInfo(wrapperInfo) { + const returnHasTypeInfo = wrapperInfo.ReturnSignature && !(getSignatureWithoutRefAndPrefix(wrapperInfo.ReturnSignature) in PrimitiveSignatureCppTypeMap) + const ret = []; + let i = 0; + if (returnHasTypeInfo) { + ret.push(`auto TIret = wrapData->TypeInfos[${i++}];`); + } + listToJsArray(wrapperInfo.ParameterSignatures).forEach((ps, index) => { + if (!(getSignatureWithoutRefAndPrefix(ps) in PrimitiveSignatureCppTypeMap)) { + ret.push(`auto TIp${index} = wrapData->TypeInfos[${i++}];`); + } + }) + return ret.join('\n ') +} + +export function checkJSArg(signature, index) { + let ret = '' + let typeInfoVar = `TIp${index}`; + if (signature[0] == "D") { + ret += `if (js_args_len > ${index} && ` + signature = signature.substring(1); + } else if (signature[0] == 'V') { + const elmSignature = signature.substring(1); + const elmClassDecl = (elmSignature == 'o' || elmSignature == 'O' || elmSignature == 'a' || + ((elmSignature.startsWith(sigs.StructPrefix) || elmSignature.startsWith(sigs.NullableStructPrefix)) && elmSignature.endsWith('_')) + ) ? `auto ${typeInfoVar}_V = il2cpp::vm::Class::GetElementClass(${typeInfoVar});` : ''; + ret += `${elmClassDecl}if (js_args_len > ${index} && ` + signature = elmSignature; + typeInfoVar += '_V'; + } else { + ret += `if (` + } + + if (signature in PrimitiveSignatureCppTypeMap) { + ret += `!converter::Converter<${PrimitiveSignatureCppTypeMap[signature]}>::accept(env, _sv${index})) return false;` + } else if (signature == 'p' || signature == 'Pv' || signature == 'a') { // IntPtr, void*, ArrayBuffer + ret += `!pesapi_is_binary(env, _sv${index}) && !pesapi_is_null(env, _sv${index}) && !pesapi_is_undefined(env, _sv${index})) return false;` + } else if (signature[0] == 'P') { + ret += `!pesapi_is_object(env, _sv${index})) return false;` + } else if (signature == 's') { + ret += `!converter::Converter::accept(env, _sv${index})) return false;` + } else if (signature == 'o' || signature == 'a') { + ret += `!DataTransfer::IsAssignable(env, _sv${index}, ${typeInfoVar}, false)) return false;` + } else if (signature == 'O') {//System.Object + return ''; + } else if ((signature.startsWith(sigs.StructPrefix) || signature.startsWith(sigs.NullableStructPrefix)) && signature.endsWith('_')) { + ret += `!DataTransfer::IsAssignable(env, _sv${index}, ${typeInfoVar}, true)) return false;` + } else { // TODO: 适配所有类型,根据!!true去查找没处理的 + ret += '!!true) return false;'; + } + return ret; +} + +export function refSetback(signature, index) { + if (signature[0] == 'P' && signature != 'Pv') { + const elementSignature = signature.substring(1); + var val = CSValToJSVal(elementSignature, `*p${index}`) + + if (val) { + if (elementSignature.startsWith(sigs.StructPrefix) && elementSignature.endsWith('_')) { + // 这个 == 的判断是因为如果外部如果传了指针进来,此时指针指向的内容已经变了,不需要重设 + // this '==' is because if a pointer is passed in from external, the content of the pointer is changed and dont need to setback. + return `if (p${index} == &up${index}) + { + pesapi_update_boxed_value(env, _sv${index}, ${val}); + } + `; + } else if (elementSignature.startsWith(sigs.NullableStructPrefix) && elementSignature.endsWith('_')) { + return `if (p${index} == &up${index}) + { + if (!p${index}->hasValue) pesapi_update_boxed_value(env, _sv${index}, pesapi_create_null(env)); + if (p${index} == &up${index}) pesapi_update_boxed_value(env, _sv${index}, ${val}); + } + `; + + } else { + return `pesapi_update_boxed_value(env, _sv${index}, ${val});`; + } + } + } + + return ''; +} + +export function returnToJS(signature) { + return `pesapi_add_return(info, ${CSValToJSVal(signature, 'ret')});`; +} + +export function returnToCS(signature) { + return ` +${JSValToCSVal(signature, 'jsret', 'ret')} + return ret; + ` +} + +export function JSValToCSVal(signature, JSName, CSName) { + if (signature == 's') { // string + return ` // JSValToCSVal s + Il2CppString* ${CSName} = converter::Converter::toCpp(env, ${JSName});`; + + } else if (signature == 'Ps') { // string ref + return ` // JSValToCSVal Ps + Il2CppString* u${CSName} = converter::Converter>::toCpp(env, ${JSName}); // string ref + Il2CppString** ${CSName} = &u${CSName}; + ` + } else if (signature == 'o' || signature == 'O' || signature == 'a') { // object + return ` // JSValToCSVal o/O + Il2CppObject* ${CSName} = JsValueToCSRef(TI${CSName}, env, ${JSName});`; + + } else if (signature == 'Po' || signature == 'PO' || signature == 'Pa') { + return ` // JSValToCSVal Po/PO + Il2CppObject* u${CSName} = DataTransfer::GetPointer(env, pesapi_unboxing(env, ${JSName})); // object ref + Il2CppObject** ${CSName} = &u${CSName}; + ` + } else if ((signature.startsWith(sigs.StructPrefix) || signature.startsWith(sigs.NullableStructPrefix)) && signature.endsWith('_')) { //valuetype + return ` // JSValToCSVal struct + ${signature}* p${CSName} = DataTransfer::GetPointer<${signature}>(env, ${JSName}); + ${signature} ${CSName} = p${CSName} ? *p${CSName} : ${signature} {};` + + } else if ((signature.startsWith('P' + sigs.StructPrefix) || signature.startsWith('P' + sigs.NullableStructPrefix)) && signature.endsWith('_')) { //valuetype ref + const S = signature.substring(1); + return ` // JSValToCSVal Pstruct + ${S}* ${CSName} = DataTransfer::GetPointer<${S}>(env, pesapi_unboxing(env, ${JSName})); // valuetype ref + ${S} u${CSName}; + if (!${CSName}) { + memset(&u${CSName}, 0, sizeof(${S})); + ${CSName} = &u${CSName}; + } + ` + } else if (signature[0] == 'P' && signature != 'Pv') { + const S = signature.substring(1); + if (S in PrimitiveSignatureCppTypeMap) { + return ` // JSValToCSVal P primitive + ${SToCPPType(S)} u${CSName} = ${getArgValue(S, JSName, true)}; + ${SToCPPType(S)}* ${CSName} = &u${CSName};` + } else { + return ` // JSValToCSVal P not primitive + ${SToCPPType(signature)} ${CSName} = ${getArgValue(S, JSName, true)};` + } + } else if (signature[0] == 'V') { + const si = signature.substring(1); + const start = parseInt(JSName.match(/_sv(\d+)/)[1]); + if (si in PrimitiveSignatureCppTypeMap) { + return ` // JSValToCSVal primitive params + Il2CppArray* ${CSName} = Params<${PrimitiveSignatureCppTypeMap[si]}>::PackPrimitive(env, info, TI${CSName}, js_args_len, ${start}); + ` + } else if (si == 's') { + return ` // JSValToCSVal string params + Il2CppArray* ${CSName} = Params::PackString(env, info, TI${CSName}, js_args_len, ${start}); + ` + } else if (si == 'o' || si == 'O' || si == 'a') { + return ` // JSValToCSVal ref params + Il2CppArray* ${CSName} = Params::PackRef(env, info, TI${CSName}, js_args_len, ${start}); + ` + } else if ((si.startsWith(sigs.StructPrefix) || si.startsWith(sigs.NullableStructPrefix)) && si.endsWith('_')) { + return ` // JSValToCSVal valuetype params + Il2CppArray* ${CSName} = Params<${si}>::PackValueType(env, info, TI${CSName}, js_args_len, ${start}); + ` + } else { + return ` // JSValToCSVal unknow params type + Il2CppArray* ${CSName} = nullptr; + ` + } + } else if (signature[0] == 'D') { + const si = signature.substring(1); + const start = parseInt(JSName.match(/_sv(\d+)/)[1]); + if (si in PrimitiveSignatureCppTypeMap) { + return ` // JSValToCSVal primitive with default + ${PrimitiveSignatureCppTypeMap[si]} ${CSName} = OptionalParameter<${PrimitiveSignatureCppTypeMap[si]}>::GetPrimitive(env, info, method, wrapData, js_args_len, ${start}); + ` + } else if (si == 's') { + return ` // JSValToCSVal string with default + Il2CppString* ${CSName} = OptionalParameter::GetString(env, info, method, wrapData, js_args_len, ${start}); + ` + } else if (si == 'o' || si == 'O' || si == 'a') { + return ` // JSValToCSVal ref with default + Il2CppObject* ${CSName} = OptionalParameter::GetRefType(env, info, method, wrapData, js_args_len, ${start}, TI${CSName}); + ` + } else if ((si.startsWith(sigs.StructPrefix) || si.startsWith(sigs.NullableStructPrefix)) && si.endsWith('_')) { + return ` // JSValToCSVal valuetype with default + ${si} ${CSName} = OptionalParameter<${si}>::GetValueType(env, info, method, wrapData, js_args_len, ${start}); + ` + } else { + return ` // JSValToCSVal unknow type with default + void* ${CSName} = nullptr; + ` + } + } else { + return ` // JSValToCSVal P any + ${SToCPPType(signature)} ${CSName} = ${getArgValue(signature, JSName)};` + } +} + +export function CSValToJSVal(signature, CSName) { + const TIName = `TI${CSName[0] == '*' ? CSName.substring(1) : CSName}`; + if (signature in PrimitiveSignatureCppTypeMap) { + return `converter::Converter<${PrimitiveSignatureCppTypeMap[signature]}>::toScript(env, ${CSName})`; + } else if (signature == 'O') { // System.Object + return `CSRefToJsValue(env, ${TIName}, ${CSName})`; + } else if (signature == 'o') { // classes except System.Object + return `CSRefToJsValue(env, ${TIName}, ${CSName})`; + } else if (signature == 'a') { // ArrayBuffer + return `CSRefToJsValue(env, ${TIName}, ${CSName})`; + } else if (signature.startsWith(sigs.NullableStructPrefix) && signature.endsWith('_')) { + return `DataTransfer::CopyNullableValueType(env, ${CSName}, ${TIName})` + } else if (signature == 's') { // string + return `converter::Converter::toScript(env, ${CSName})`; + } else if (signature == 'p' || signature == 'Pv') { // IntPtr, void* + return `pesapi_create_binary(env, ${CSName}, 0)`; + } else if (signature.startsWith(sigs.StructPrefix) && signature.endsWith('_')) { + return `DataTransfer::CopyValueType(env, ${CSName}, ${TIName})` + } else { //TODO: 能处理的就处理, DateTime是否要处理呢? + return `// unknow ret signature: ${signature}` + } +} + + +export function genArgsLenCheck(parameterSignatures) { + var requireNum = 0; + for (; requireNum < parameterSignatures.length && parameterSignatures[requireNum][0] != 'V' && parameterSignatures[requireNum][0] != 'D'; ++requireNum) { } + return requireNum != parameterSignatures.length ? `js_args_len < ${requireNum}` : `js_args_len != ${parameterSignatures.length}`; +} + diff --git a/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/Puerts_il2cpp.cpp.txt b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/Puerts_il2cpp.cpp.txt index f835ef4d65..6e789e46eb 100644 --- a/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/Puerts_il2cpp.cpp.txt +++ b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/Puerts_il2cpp.cpp.txt @@ -1612,6 +1612,17 @@ Il2CppObject* GetJSObjectValue(Il2CppObject* jsObject, Il2CppString* key, Il2Cpp return g_unityExports.GetJSObjectValue(objectInfo, key_std.c_str(), type); } +WrapFuncPtr FindWrapFunc(const char* signature); +struct FieldWrapFuncInfo * FindFieldWrapFuncInfo(const char* signature); + +void IL2cppLog(const char* value) +{ + if (g_unityExports.LogCallback) + { + g_unityExports.LogCallback(value); + } +} + puerts::UnityExports* GetUnityExports() { g_unityExports.ObjectAllocate = &ObjectAllocate; @@ -1648,6 +1659,8 @@ puerts::UnityExports* GetUnityExports() g_unityExports.ReflectionGetFieldWrapper = ReflectionGetFieldWrapper; g_unityExports.ReflectionSetFieldWrapper = ReflectionSetFieldWrapper; g_unityExports.SizeOfRuntimeObject = sizeof(RuntimeObject); + g_unityExports.FindWrapFunc = FindWrapFunc; + g_unityExports.FindFieldWrapFuncInfo = FindFieldWrapFuncInfo; return &g_unityExports; } diff --git a/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/TDataTrans.h.txt b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/TDataTrans.h.txt new file mode 100644 index 0000000000..3fa3f0a351 --- /dev/null +++ b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/TDataTrans.h.txt @@ -0,0 +1,498 @@ +/* +* Tencent is pleased to support the open source community by making Puerts available. +* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. +* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. +* This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. +*/ + +#include "pesapi.h" + +namespace puerts +{ +// begin function in Puerts_il2cpp.cpp +Il2CppObject* JsValueToCSRef(Il2CppClass *klass, pesapi_env env, pesapi_value jsval); + +pesapi_value CSRefToJsValue(pesapi_env env, Il2CppClass *targetClass, Il2CppObject* obj); + +void* GetDefaultValuePtr(const MethodInfo* method, uint32_t index); + +Il2CppClass* GetReturnType(const MethodInfo* method); + +Il2CppClass* GetParameterType(const MethodInfo* method, int index); + +void GetFieldValue(void *ptr, FieldInfo *field, size_t offset, void *value); + +void* GetValueTypeFieldPtr(void *obj, FieldInfo *field, size_t offset); + +void SetFieldValue(void *ptr, FieldInfo *field, size_t offset, void *value); + +void IL2cppLog(const char* value); + +// end function in Puerts_il2cpp.cpp + +struct PObjectRefInfo +{ + pesapi_env_ref EnvRef; + pesapi_value_ref ValueRef; +}; + +#define GetPObjectRefInfo(Value) ((PObjectRefInfo*)(((uint8_t*)Value) + sizeof(RuntimeObject))) + +class AutoValueScope +{ +public: + AutoValueScope(pesapi_env_ref env_holder) + { + scope = pesapi_open_scope(env_holder); + } + + ~AutoValueScope() + { + pesapi_close_scope(scope); + } + + pesapi_scope scope; +}; + +struct DataTransfer +{ + static bool IsDelegate(Il2CppClass *klass) + { + return il2cpp::vm::Class::IsAssignableFrom(il2cpp_defaults.delegate_class, klass) && klass != il2cpp_defaults.delegate_class && klass != il2cpp_defaults.multicastdelegate_class; + } + + static bool IsAssignable(pesapi_env env, pesapi_value value, Il2CppClass *klass, bool isvaluetype) + { + if (!isvaluetype && (pesapi_is_null(env, value) || pesapi_is_undefined(env, value))) + { + return true; + } + if (IsDelegate(klass) && pesapi_is_function(env, value)) + { + return true; + } + auto objClass = (Il2CppClass*) pesapi_get_native_object_typeid(env, value); + return objClass && il2cpp::vm::Class::IsAssignableFrom(klass, objClass); + } + + template + static T* GetPointer(pesapi_env env, pesapi_value value) + { + if (pesapi_is_null(env, value) || pesapi_is_undefined(env, value)) + { + return nullptr; + } + return static_cast(pesapi_get_native_object_ptr(env, value)); + } + + template + static pesapi_value CopyValueType(pesapi_env env, const T &v, const void* type_id) + { + T* ret = new T; + memcpy(ret, &v, sizeof(T)); + return pesapi_native_object_to_value(env, type_id, ret, true); + } + + template + static pesapi_value CopyNullableValueType(pesapi_env env, const T &v, const void* type_id) + { + if (!v.hasValue) + { + return pesapi_create_null(env); + } + return CopyValueType(env, v.p1, type_id); + } +}; + +struct WrapFuncInfo +{ + const char* Signature; + WrapFuncPtr Method; +}; + +struct BridgeFuncInfo +{ + const char* Signature; + MethodPointer Method; +}; + +struct FieldWrapFuncInfo +{ + const char* Signature; + FieldWrapFuncPtr Getter; + FieldWrapFuncPtr Setter; +}; + +namespace converter +{ + +template +struct Converter; + + +template +struct Converter::value && sizeof(T) == 8 && std::is_signed::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(pesapi_get_value_int64(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_int64(env, value); + } +}; + +template +struct Converter::value && sizeof(T) == 8 && !std::is_signed::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(pesapi_get_value_uint64(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_uint64(env, value); + } +}; + +template +struct Converter::value && sizeof(T) < 8 && std::is_signed::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(pesapi_get_value_int32(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_int32(env, value); + } +}; + +template +struct Converter::value && sizeof(T) < 8 && !std::is_signed::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(pesapi_get_value_uint32(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_uint32(env, value); + } +}; + +template +struct Converter::value>::type> +{ + static pesapi_value toScript(pesapi_env env, T value) + { + return pesapi_create_int32(env, static_cast(value)); + } + + static T toCpp(pesapi_env env, pesapi_value value) + { + return static_cast(pesapi_get_value_int32(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_int32(env, value); + } +}; + +template +struct Converter::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(pesapi_get_value_double(env, value)); + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_double(env, value); + } +}; + +template <> +struct Converter +{ + 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 +{ + 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 <> +struct Converter +{ + static pesapi_value toScript(pesapi_env env, Il2CppString* value) + { + if (value == nullptr) + { + return pesapi_create_null(env); + } + const Il2CppChar* utf16 = il2cpp::utils::StringUtils::GetChars(value); + std::string str = il2cpp::utils::StringUtils::Utf16ToUtf8(utf16); + return pesapi_create_string_utf8(env, str.c_str(), str.size()); + } + + static Il2CppString* toCpp(pesapi_env env, pesapi_value value) + { + if (pesapi_is_null(env, value) || pesapi_is_undefined(env, value)) + { + return nullptr; + } + size_t bufsize = 0; + auto str = pesapi_get_value_string_utf8(env, value, nullptr, &bufsize); + if (str) + { + return il2cpp::vm::String::NewWrapper(str); + } + std::vector buff; + buff.resize(bufsize + 1); + str = pesapi_get_value_string_utf8(env, value, buff.data(), &bufsize); + if (str) + { + buff[bufsize] = '\0'; + return il2cpp::vm::String::NewWrapper(str); + } + return nullptr; + } + + static bool accept(pesapi_env env, pesapi_value value) + { + return pesapi_is_string(env, value) || pesapi_is_null(env, value) || pesapi_is_undefined(env, value); + } +}; + +template +struct Converter> +{ + static pesapi_value toScript(pesapi_env env, const T& value) + { + return pesapi_boxing(env, Converter::toScript(env, value)); + } + + static T toCpp(pesapi_env env, pesapi_value value) + { + return Converter::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 +struct OptionalParameter +{ + static T GetPrimitive(pesapi_env env, pesapi_callback_info info, MethodInfo* methodInfo, puerts::WrapData* wrapData, int length, int index) + { + if (index < length) + { + return converter::Converter::toCpp(env, pesapi_get_arg(info, index)); + } + else + { + if (wrapData->IsExtensionMethod) ++index; + auto pret = (T*)GetDefaultValuePtr(methodInfo, index); + if (pret) + { + return *pret; + } + return {}; + } + } + + static T GetValueType(pesapi_env env, pesapi_callback_info info, MethodInfo* methodInfo, puerts::WrapData* wrapData, int length, int index) + { + if (index < length) + { + return (*DataTransfer::GetPointer(env, pesapi_get_arg(info, index))); + } + else + { + if (wrapData->IsExtensionMethod) ++index; + auto pret = (T*)GetDefaultValuePtr(methodInfo, index); + if (pret) + { + return *pret; + } + T ret; + memset(&ret, 0, sizeof(T)); + return ret; + } + } + + static Il2CppString* GetString(pesapi_env env, pesapi_callback_info info, MethodInfo* methodInfo, puerts::WrapData* wrapData, int length, int index) + { + if (index < length) + { + return converter::Converter::toCpp(env, pesapi_get_arg(info, index)); + } + else + { + if (wrapData->IsExtensionMethod) ++index; + return (Il2CppString*)GetDefaultValuePtr(methodInfo, index); + } + } + + static Il2CppObject* GetRefType(pesapi_env env, pesapi_callback_info info, MethodInfo* methodInfo, puerts::WrapData* wrapData, int length, int index, Il2CppClass* typeId) + { + if (index < length) + { + return JsValueToCSRef(typeId, env, pesapi_get_arg(info, index)); + } + else + { + if (wrapData->IsExtensionMethod) ++index; + return (Il2CppObject*)GetDefaultValuePtr(methodInfo, index); + } + } +}; + + +template +struct Params +{ + static Il2CppArray* PackPrimitive(pesapi_env env, pesapi_callback_info info, Il2CppClass* typeId, int length, int start) + { + Il2CppArray* ret = il2cpp::vm::Array::NewSpecific(typeId, length - start > 0 ? length - start : 0); + T* arr = reinterpret_cast(il2cpp::vm::Array::GetFirstElementAddress(ret)); + for(int i = start; i < length;++i) + { + arr[i - start] = converter::Converter::toCpp(env, pesapi_get_arg(info, i)); + } + return ret; + } + + static Il2CppArray* PackString(pesapi_env env, pesapi_callback_info info, Il2CppClass* typeId, int length, int start) + { + Il2CppArray* ret = il2cpp::vm::Array::NewSpecific(typeId, length - start > 0 ? length - start : 0); + for(int i = start; i < length;++i) + { + il2cpp_array_setref(ret, i - start, converter::Converter::toCpp(env, pesapi_get_arg(info, i))); + } + return ret; + } + + static Il2CppArray* PackRef(pesapi_env env, pesapi_callback_info info, Il2CppClass* typeId, int length, int start) + { + Il2CppArray* ret = il2cpp::vm::Array::NewSpecific(typeId, length - start > 0 ? length - start : 0); + auto elemTypeId = il2cpp::vm::Class::GetElementClass(typeId); + for(int i = start; i < length;++i) + { + il2cpp_array_setref(ret, i - start, JsValueToCSRef(elemTypeId, env, pesapi_get_arg(info, i))); + } + return ret; + } + + static Il2CppArray* PackValueType(pesapi_env env, pesapi_callback_info info, Il2CppClass* typeId, int length, int start) + { + Il2CppArray* ret = il2cpp::vm::Array::NewSpecific(typeId, length - start > 0 ? length - start : 0); + T* arr = reinterpret_cast(il2cpp::vm::Array::GetFirstElementAddress(ret)); + for(int i = start; i < length;++i) + { + T* e = DataTransfer::GetPointer(env, pesapi_get_arg(info, i)); + if (!e) continue; + arr[i - start] = *e; + } + return ret; + } + + + static void UnPackPrimitive(pesapi_env env, Il2CppArray* array, uint32_t arrayLength, Il2CppClass* typeId, pesapi_value* argv) + { + T* arr = reinterpret_cast(il2cpp::vm::Array::GetFirstElementAddress(array)); + for (uint32_t i = 0; i < arrayLength; ++i) + { + argv[i] = converter::Converter::toScript(env, arr[i]); + } + } + + static void UnPackRefOrBoxedValueType(pesapi_env env, Il2CppArray* array, uint32_t arrayLength, Il2CppClass* typeId, pesapi_value* argv) + { + Il2CppObject** arr = reinterpret_cast(il2cpp::vm::Array::GetFirstElementAddress(array)); + for (uint32_t i = 0; i < arrayLength; ++i) + { + argv[i] = CSRefToJsValue(env, typeId, arr[i]); + } + } + + static void UnPackValueType(pesapi_env env, Il2CppArray* array, uint32_t arrayLength, Il2CppClass* typeId, pesapi_value* argv) + { + T* arr = reinterpret_cast(il2cpp::vm::Array::GetFirstElementAddress(array)); + auto elemTypeId = il2cpp::vm::Class::GetElementClass(typeId); + for (uint32_t i = 0; i < arrayLength; ++i) + { + argv[i] = DataTransfer::CopyValueType(env, &arr[i], elemTypeId); + } + } + +}; + +} \ No newline at end of file diff --git a/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/UnityExports4Puerts.h.txt b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/UnityExports4Puerts.h.txt index 3b087afe0d..47a6540490 100644 --- a/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/UnityExports4Puerts.h.txt +++ b/unity/Assets/core/upm/Editor/Resources/puerts/xil2cpp/UnityExports4Puerts.h.txt @@ -148,6 +148,12 @@ typedef void* (*GetRuntimeObjectFromPersistentObjectFunc)(pesapi_env env, pesapi typedef void (*SetRuntimeObjectToPersistentObjectFunc)(pesapi_env env, pesapi_value pvalue, void* runtimeObject); +typedef WrapFuncPtr (*FindWrapFuncFunc)(const char* signature); + +typedef struct FieldWrapFuncInfo * (*FindFieldWrapFuncInfoFunc)(const char* signature); + +typedef void(*LogCallbackFunc)(const char* value); + struct WrapData { WrapFuncPtr Wrap; @@ -221,6 +227,10 @@ struct UnityExports GetRuntimeObjectFromPersistentObjectFunc GetRuntimeObjectFromPersistentObject = nullptr; SetRuntimeObjectToPersistentObjectFunc SetRuntimeObjectToPersistentObject = nullptr; + LogCallbackFunc LogCallback = nullptr; + + FindWrapFuncFunc FindWrapFunc = nullptr; + FindFieldWrapFuncInfoFunc FindFieldWrapFuncInfo = nullptr; }; } \ No newline at end of file diff --git a/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/FileExporter.cs b/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/FileExporter.cs index 9d897f9852..33b759ceb3 100644 --- a/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/FileExporter.cs +++ b/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/FileExporter.cs @@ -145,7 +145,7 @@ private static bool IterateAllValueType(Type type, List list) return true; } - public static void GenCPPWrap(string saveTo, bool onlyConfigure = false) + public static void GenCPPWrap(string templatePath, string saveTo, bool onlyConfigure = false) { Utils.SetFilters(Puerts.Configure.GetFilters()); @@ -364,8 +364,8 @@ where type.IsPublic using (var jsEnv = new Puerts.JsEnv()) { jsEnv.UsingFunc(); - var cppWrapRender = jsEnv.ExecuteModule>("puerts/templates/cppwrapper.tpl.mjs", "default"); - using (StreamWriter textWriter = new StreamWriter(Path.Combine(saveTo, "FunctionBridge.Gen.h"), false, Encoding.UTF8)) + var cppWrapRender = jsEnv.ExecuteModule>(templatePath, "default"); + using (StreamWriter textWriter = new StreamWriter(saveTo, false, Encoding.UTF8)) { string fileContext = cppWrapRender(new CppWrappersInfo { @@ -448,7 +448,8 @@ public static void CopyXIl2cppCPlugin(string outDir) { "pesapi_adpt.c", Resources.Load("puerts/xil2cpp/pesapi_adpt.c").text }, { "pesapi.h", Resources.Load("puerts/xil2cpp/pesapi.h").text }, { "Puerts_il2cpp.cpp", Resources.Load("puerts/xil2cpp/Puerts_il2cpp.cpp").text }, - { "UnityExports4Puerts.h", Resources.Load("puerts/xil2cpp/UnityExports4Puerts.h").text } + { "UnityExports4Puerts.h", Resources.Load("puerts/xil2cpp/UnityExports4Puerts.h").text }, + { "TDataTrans.h", Resources.Load("puerts/xil2cpp/TDataTrans.h").text } }; foreach (var cPlugin in cPluginCode) diff --git a/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/UnityMenu.cs b/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/UnityMenu.cs index 1912ac161e..9b7f60993c 100644 --- a/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/UnityMenu.cs +++ b/unity/Assets/core/upm/Editor/Src/Generator/IL2Cpp/UnityMenu.cs @@ -45,6 +45,7 @@ public static void GenerateCppPlugin() Directory.CreateDirectory(saveTo); FileExporter.CopyXIl2cppCPlugin(saveTo); FileExporter.GenMarcoHeader(saveTo); + FileExporter.GenCPPWrap("puerts/templates/il2cppwrapper.tpl.mjs", Path.Combine(saveTo, "PuertsIl2cppWrapper.cpp"), true); } [MenuItem(Puerts.Editor.Generator.UnityMenu.PUERTS_MENU_PREFIX + "/Generate/xIl2cpp FunctionBridge.Gen.h", false, 6)] @@ -60,7 +61,7 @@ public static void GenerateCppWrappers() #endif Directory.CreateDirectory(saveTo); - FileExporter.GenCPPWrap(saveTo); + FileExporter.GenCPPWrap("puerts/templates/cppwrapper.tpl.mjs", Path.Combine(saveTo, "FunctionBridge.Gen.h")); Debug.Log("finished! use " + (DateTime.Now - start).TotalMilliseconds + " ms Outputed to " + saveTo); } @@ -77,7 +78,7 @@ public static void GenerateCppWrappersInConfigure() #endif Directory.CreateDirectory(saveTo); - FileExporter.GenCPPWrap(saveTo, true); + FileExporter.GenCPPWrap("puerts/templates/cppwrapper.tpl.mjs", Path.Combine(saveTo, "FunctionBridge.Gen.h"), true); Debug.Log("finished! use " + (DateTime.Now - start).TotalMilliseconds + " ms Outputed to " + saveTo); } diff --git a/unity/native_src_il2cpp/Src/Puerts.cpp b/unity/native_src_il2cpp/Src/Puerts.cpp index 06cec1049c..f9c2fe3493 100644 --- a/unity/native_src_il2cpp/Src/Puerts.cpp +++ b/unity/native_src_il2cpp/Src/Puerts.cpp @@ -902,9 +902,13 @@ static void SetParamArrayFlagAndOptionalNum(puerts::WrapData* data, const char* V8_EXPORT puerts::WrapFuncPtr FindWrapFunc(const char* signature) { if (signature == nullptr) + { return puerts::GUnityExports.ReflectionWrapper; + } else - return puerts::FindWrapFunc(signature); + { + return puerts::GUnityExports.FindWrapFunc(signature); + } } V8_EXPORT puerts::WrapData* AddConstructor(puerts::JsClassInfo* classInfo, const char* signature, puerts::WrapFuncPtr WrapFunc, void* method, puerts::MethodPointer methodPointer, int typeInfoNum) @@ -974,9 +978,10 @@ V8_EXPORT puerts::FieldWrapFuncInfo* FindFieldWrap(const char* signature) return ReflectionFuncWrap; } - else - return puerts::FindFieldWrapFuncInfo(signature); + { + return puerts::GUnityExports.FindFieldWrapFuncInfo(signature); + } } V8_EXPORT bool AddField(puerts::JsClassInfo* classInfo, puerts::FieldWrapFuncInfo* wrapFuncInfo, const char* name, bool is_static, void* fieldInfo, int offset, void* fieldTypeInfo) @@ -1146,6 +1151,7 @@ V8_EXPORT void ExchangeAPI(puerts::UnityExports * exports) exports->GetRuntimeObjectFromPersistentObject = &puerts::GetRuntimeObjectFromPersistentObject; exports->GetJSObjectValue = &puerts::GetJSObjectValue; exports->GetModuleExecutor = &puerts::GetModuleExecutor; + exports->LogCallback = puerts::GLogCallback; puerts::GUnityExports = *exports; }