Compare commits
305 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
434160afa8 | |
|
|
01754c8fb4 | |
|
|
1934d90f27 | |
|
|
814572e1a1 | |
|
|
d505624c78 | |
|
|
e36bbb9022 | |
|
|
0642726469 | |
|
|
d86572db37 | |
|
|
b5944ea834 | |
|
|
73654e76d2 | |
|
|
1537690bb5 | |
|
|
7f158f814a | |
|
|
ee7af5c592 | |
|
|
ab41cd0144 | |
|
|
59a3c3974a | |
|
|
c9ff293dfe | |
|
|
56486b8a76 | |
|
|
8e27e8d41b | |
|
|
fca130bbfa | |
|
|
c21dbcc60a | |
|
|
7f2fa52f37 | |
|
|
da46e71534 | |
|
|
804418fddb | |
|
|
7a0032934b | |
|
|
b301b44cd3 | |
|
|
ddc3332958 | |
|
|
52f25bdb2a | |
|
|
31be818bb6 | |
|
|
213a11ff25 | |
|
|
585be97be9 | |
|
|
361873803f | |
|
|
46f308ed5e | |
|
|
34406b1c13 | |
|
|
e5b52922f7 | |
|
|
e44fa663db | |
|
|
903cf9faa2 | |
|
|
3fe41a8cba | |
|
|
603b0ccb24 | |
|
|
9429a4d24d | |
|
|
ea592ba20c | |
|
|
8d1280a1bd | |
|
|
528240b52b | |
|
|
4768c039d2 | |
|
|
10dc749d7a | |
|
|
0c5ef00c12 | |
|
|
1553582ec1 | |
|
|
756b906a21 | |
|
|
355e24fbe8 | |
|
|
9e4946aa45 | |
|
|
8e571d594d | |
|
|
b8dd2be1e4 | |
|
|
de7b60695a | |
|
|
a11ebecf93 | |
|
|
019412fa81 | |
|
|
84bf6d59db | |
|
|
82163d2e50 | |
|
|
208372e6af | |
|
|
dd8d812641 | |
|
|
c19b34542e | |
|
|
e30306d7e1 | |
|
|
20f34c9b14 | |
|
|
45749ffb5c | |
|
|
b176d63d93 | |
|
|
0c99afd58e | |
|
|
2458c9a9ba | |
|
|
4d0fef095b | |
|
|
642d2cd644 | |
|
|
e54ce36b0e | |
|
|
ac8b649d50 | |
|
|
9ca9cd5aa7 | |
|
|
37dafd7b3c | |
|
|
f58d12c2cb | |
|
|
d5eaa350c5 | |
|
|
1f0053a3c9 | |
|
|
15dccc7427 | |
|
|
7d287a2293 | |
|
|
f19ba3eb30 | |
|
|
4e172129d8 | |
|
|
2414e77fef | |
|
|
77517a9814 | |
|
|
162f21f6a5 | |
|
|
bd7c3293bc | |
|
|
e25be945c7 | |
|
|
925921c27c | |
|
|
64a6d26fa3 | |
|
|
c24617d864 | |
|
|
59bc259cc8 | |
|
|
c413cd6143 | |
|
|
c614cdcf4e | |
|
|
08f493ab3e | |
|
|
3705ca6e1f | |
|
|
34df279943 | |
|
|
b85ed1aa92 | |
|
|
faf4a328af | |
|
|
53f4f33bf0 | |
|
|
48c91f497b | |
|
|
9afbe3bd84 | |
|
|
2d5f71f6b7 | |
|
|
5747458bf2 | |
|
|
0b455eb882 | |
|
|
e086228d90 | |
|
|
909e96ca7c | |
|
|
75b24345f6 | |
|
|
88e20505f8 | |
|
|
b4b486944c | |
|
|
360ba38805 | |
|
|
e5a6952777 | |
|
|
9330cf682c | |
|
|
16a7d5d529 | |
|
|
303c6c7b35 | |
|
|
e4cf9e9086 | |
|
|
b977a85b23 | |
|
|
0fcb51a369 | |
|
|
d61511924d | |
|
|
aca7dd0a67 | |
|
|
fc685a99ca | |
|
|
d431aeb019 | |
|
|
63d0aaa6e6 | |
|
|
d45974c6b4 | |
|
|
3de931a3af | |
|
|
b96d6fc10d | |
|
|
ef1b78caae | |
|
|
47622bf49c | |
|
|
846d7103a3 | |
|
|
170f13082e | |
|
|
60016d7481 | |
|
|
97dae7fed2 | |
|
|
f935127cd3 | |
|
|
ec5f2ef05e | |
|
|
6d0ceaa4f5 | |
|
|
95922aec1e | |
|
|
3259c11828 | |
|
|
74bab1d935 | |
|
|
fd81edb495 | |
|
|
12bafb897f | |
|
|
a6befb1312 | |
|
|
a36e3fe72d | |
|
|
d9776d1793 | |
|
|
2697eb5a90 | |
|
|
4879bb7f44 | |
|
|
24f85780a2 | |
|
|
6c679cc3ab | |
|
|
20a06f1ec5 | |
|
|
5446bd937c | |
|
|
ae88dd0eec | |
|
|
a5c006d67c | |
|
|
67c487f521 | |
|
|
6ffb977ef3 | |
|
|
f59ba2623a | |
|
|
4b57138935 | |
|
|
276cd0a4a8 | |
|
|
22a9793b9d | |
|
|
1b7947b196 | |
|
|
188fdc9430 | |
|
|
ff0f225423 | |
|
|
36ca398543 | |
|
|
f30e2f5b33 | |
|
|
a531a213c2 | |
|
|
2b42376505 | |
|
|
ef103d8351 | |
|
|
db87b92f78 | |
|
|
51da1d4c43 | |
|
|
71ad34d7ac | |
|
|
7c29ab804b | |
|
|
9b269ea4c2 | |
|
|
c9ad6880cb | |
|
|
372fa9e06e | |
|
|
3df95d138d | |
|
|
410bb9b542 | |
|
|
15155b9a46 | |
|
|
f810ede6d7 | |
|
|
63d9e7f4c3 | |
|
|
3cea936aa4 | |
|
|
d90faed922 | |
|
|
febff1c658 | |
|
|
94a329a522 | |
|
|
84ed2e6b9d | |
|
|
47fbd443c1 | |
|
|
d5b52cc8db | |
|
|
d9ed27abfb | |
|
|
f51c2803c1 | |
|
|
05a34d4d12 | |
|
|
216d09f7b6 | |
|
|
8d441a02d2 | |
|
|
de2bc21f20 | |
|
|
4aba5c2a5e | |
|
|
b573e61504 | |
|
|
69de3d733d | |
|
|
a77ed7369a | |
|
|
1bd27a3e22 | |
|
|
4da7c1a524 | |
|
|
5c750e9c02 | |
|
|
cc09487671 | |
|
|
b024a18ba1 | |
|
|
4587cb7c19 | |
|
|
beec0b73e6 | |
|
|
61fb0cfe34 | |
|
|
260909bd4b | |
|
|
06a250b9fa | |
|
|
dc884d36b8 | |
|
|
1168d51e93 | |
|
|
7270e9194d | |
|
|
1d50dfcb6e | |
|
|
1eaaf44c97 | |
|
|
9cf8f19517 | |
|
|
22760c6c7c | |
|
|
47e43b0afa | |
|
|
58c7073073 | |
|
|
9dafabd1ee | |
|
|
5857696b56 | |
|
|
f2807f4838 | |
|
|
f46c180181 | |
|
|
1e14a5f30f | |
|
|
dfa11d11c3 | |
|
|
69d3303f3d | |
|
|
9eb6dda71b | |
|
|
10e0568251 | |
|
|
1f9faf49a3 | |
|
|
3f1b34682d | |
|
|
c3f6325e4a | |
|
|
a9f5608ecf | |
|
|
8a95fd57f5 | |
|
|
679c21da43 | |
|
|
52bab856ed | |
|
|
844b2fb62f | |
|
|
88404cbbfc | |
|
|
9b4aa904ef | |
|
|
a71153d414 | |
|
|
bec8c84c56 | |
|
|
79bab0459c | |
|
|
1d09f72460 | |
|
|
058270c658 | |
|
|
210c781fad | |
|
|
6757f6df5b | |
|
|
41c73fe35b | |
|
|
4d487fa4c4 | |
|
|
2f71bb515d | |
|
|
0d8b001dd2 | |
|
|
3d68dc4db3 | |
|
|
2988aef85a | |
|
|
768512bcfa | |
|
|
4492449b73 | |
|
|
be113567ba | |
|
|
e45a789569 | |
|
|
0a82b0d339 | |
|
|
c8cd323bb0 | |
|
|
2f09f88ca2 | |
|
|
8e178c0e37 | |
|
|
40711cbf38 | |
|
|
7749b6448e | |
|
|
1459992ec4 | |
|
|
c09dad4ae1 | |
|
|
271dc70626 | |
|
|
c462aeb2ef | |
|
|
adbdbf3a00 | |
|
|
10684d29cd | |
|
|
7d58454fdd | |
|
|
21b85aa2d3 | |
|
|
8439e4176d | |
|
|
4b43870ff2 | |
|
|
b49b94521e | |
|
|
49873ba6ed | |
|
|
97f083f07d | |
|
|
941bbc723a | |
|
|
18def7886d | |
|
|
f1336c56d4 | |
|
|
8f89651d10 | |
|
|
8d0634620a | |
|
|
f5afc43625 | |
|
|
f8eee2ba49 | |
|
|
07b52bed05 | |
|
|
3139fbefa6 | |
|
|
fbeeb3d959 | |
|
|
1f4e754adb | |
|
|
f63bbc8a52 | |
|
|
b17751b8a8 | |
|
|
05e721cf02 | |
|
|
29646f1294 | |
|
|
3702411ac8 | |
|
|
d205f00a1b | |
|
|
2894701063 | |
|
|
1045538b40 | |
|
|
8fd9b2ec82 | |
|
|
0ccdd424ab | |
|
|
c083e4ada4 | |
|
|
4c6dd1249a | |
|
|
b8b990bfc1 | |
|
|
252e6add67 | |
|
|
6e76b96f97 | |
|
|
dd18ecdba5 | |
|
|
2ff3e276d2 | |
|
|
1d5f2a953c | |
|
|
75cb53cb19 | |
|
|
c84f575a2e | |
|
|
3beb788baa | |
|
|
6909c32a0c | |
|
|
bbb43c3185 | |
|
|
1159125044 | |
|
|
141ff18a7e | |
|
|
a9ca9fc613 | |
|
|
15f2f0b83c | |
|
|
d67a11b384 | |
|
|
ff93f30a69 | |
|
|
275a3bd01a | |
|
|
b5a7899657 |
|
|
@ -1,5 +0,0 @@
|
||||||
# change logs
|
|
||||||
|
|
||||||
- 2022.8.30 创建
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 22f11da50eb60c245b40028549937af6
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 33c064b00b452284f93cd6e89de8a06d
|
|
||||||
TextScriptImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "../Il2CppCompatibleDef.h"
|
||||||
|
|
||||||
|
namespace hybridclr
|
||||||
|
{
|
||||||
|
const char* g_placeHolderAssemblies[] =
|
||||||
|
{
|
||||||
|
//!!!{{PLACE_HOLDER
|
||||||
|
|
||||||
|
//!!!}}PLACE_HOLDER
|
||||||
|
nullptr,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include <codegen/il2cpp-codegen-metadata.h>
|
||||||
|
#if HYBRIDCLR_UNITY_2023_OR_NEW
|
||||||
|
#include <codegen/il2cpp-codegen.h>
|
||||||
|
#elif HYBRIDCLR_UNITY_2022
|
||||||
|
#include <codegen/il2cpp-codegen-il2cpp.h>
|
||||||
|
#elif HYBRIDCLR_UNITY_2020 || HYBRIDCLR_UNITY_2021
|
||||||
|
#include <codegen/il2cpp-codegen-common-big.h>
|
||||||
|
#else
|
||||||
|
#include <codegen/il2cpp-codegen-common.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "vm/ClassInlines.h"
|
||||||
|
#include "vm/Object.h"
|
||||||
|
#include "vm/Class.h"
|
||||||
|
#include "vm/ScopedThreadAttacher.h"
|
||||||
|
|
||||||
|
#include "../metadata/MetadataUtil.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "../interpreter/InterpreterModule.h"
|
||||||
|
#include "../interpreter/MethodBridge.h"
|
||||||
|
#include "../interpreter/Interpreter.h"
|
||||||
|
#include "../interpreter/MemoryUtil.h"
|
||||||
|
#include "../interpreter/InstrinctDef.h"
|
||||||
|
|
||||||
|
using namespace hybridclr::interpreter;
|
||||||
|
using namespace hybridclr::metadata;
|
||||||
|
|
||||||
|
//!!!{{CODE
|
||||||
|
|
||||||
|
|
||||||
|
//!!!}}CODE
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
#include <codegen/il2cpp-codegen-metadata.h>
|
|
||||||
#include "vm/ClassInlines.h"
|
|
||||||
#include "vm/Object.h"
|
|
||||||
#include "vm/Class.h"
|
|
||||||
|
|
||||||
#include "../metadata/MetadataModule.h"
|
|
||||||
#include "../metadata/MetadataUtil.h"
|
|
||||||
|
|
||||||
#include "../interpreter/MethodBridge.h"
|
|
||||||
#include "../interpreter/Interpreter.h"
|
|
||||||
#include "../interpreter/MemoryUtil.h"
|
|
||||||
#include "../interpreter/InstrinctDef.h"
|
|
||||||
|
|
||||||
using namespace hybridclr::interpreter;
|
|
||||||
|
|
||||||
#if {PLATFORM_ABI}
|
|
||||||
//!!!{{CODE
|
|
||||||
|
|
||||||
//!!!}}CODE
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
#include "../metadata/ReversePInvokeMethodStub.h"
|
|
||||||
#include "../metadata/MetadataModule.h"
|
|
||||||
|
|
||||||
namespace hybridclr
|
|
||||||
{
|
|
||||||
namespace metadata
|
|
||||||
{
|
|
||||||
#if {PLATFORM_ABI}
|
|
||||||
|
|
||||||
//!!!{{CODE
|
|
||||||
|
|
||||||
void __ReversePInvokeMethod_0(void* xState)
|
|
||||||
{
|
|
||||||
CallLuaFunction(xState, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void __ReversePInvokeMethod_1(void* xState)
|
|
||||||
{
|
|
||||||
CallLuaFunction(xState, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Il2CppMethodPointer s_ReversePInvokeMethodStub[]
|
|
||||||
{
|
|
||||||
(Il2CppMethodPointer)__ReversePInvokeMethod_0,
|
|
||||||
(Il2CppMethodPointer)__ReversePInvokeMethod_1,
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
//!!!}}CODE
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//!!!{{UNITY_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
//!!!}}UNITY_VERSION
|
||||||
|
|
@ -2,18 +2,38 @@
|
||||||
"versions": [
|
"versions": [
|
||||||
{
|
{
|
||||||
"unity_version":"2019",
|
"unity_version":"2019",
|
||||||
"hybridclr" : { "branch":"main", "hash":"531f98365eebce5d1390175be2b41c41e217d918"},
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
"il2cpp_plus": { "branch":"2019-main", "hash":"ebe5190b0404d1857832bd1d52ebec7c3730a01d"}
|
"il2cpp_plus": { "branch":"v2019-8.1.0"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unity_version":"2020",
|
"unity_version":"2020",
|
||||||
"hybridclr" : { "branch":"main", "hash":"531f98365eebce5d1390175be2b41c41e217d918"},
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
"il2cpp_plus": { "branch":"2020-main", "hash":"c6cf54285381d0b03a58126e0d39b6e4d11937b7"}
|
"il2cpp_plus": { "branch":"v2020-8.1.0"}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"unity_version":"2021",
|
"unity_version":"2021",
|
||||||
"hybridclr" : { "branch":"main", "hash":"531f98365eebce5d1390175be2b41c41e217d918"},
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
"il2cpp_plus": { "branch":"2021-main", "hash":"99cd1cbbfc1f637460379e81c9a7776cd3e662ad"}
|
"il2cpp_plus": { "branch":"v2021-8.1.0"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unity_version":"2022",
|
||||||
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
|
"il2cpp_plus": { "branch":"v2022-8.2.0"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unity_version":"2022-tuanjie",
|
||||||
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
|
"il2cpp_plus": { "branch":"v2022-tuanjie-8.6.0"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unity_version":"2023",
|
||||||
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
|
"il2cpp_plus": { "branch":"v2023-8.1.0"}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unity_version":"6000",
|
||||||
|
"hybridclr" : { "branch":"v8.6.0"},
|
||||||
|
"il2cpp_plus": { "branch":"v6000-8.1.0"}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
# file: CMakeList.txt
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET iOS)
|
|
||||||
|
|
||||||
set(TMP $ENV{HUATUO_IL2CPP_SOURCE_DIR})
|
|
||||||
if ( NOT TMP )
|
|
||||||
message(FATAL_ERROR "需要设置环境变量: HUATUO_IL2CPP_SOURCE_DIR")
|
|
||||||
else()
|
|
||||||
message(STATUS "unity il2cpp 路径为: ${TMP}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(SDK_VERSION $ENV{IPHONESIMULATOR_VERSION})
|
|
||||||
if ( SDK_VERSION )
|
|
||||||
message(STATUS "使用iPhoneSimulator版本:" ${SDK_VERSION})
|
|
||||||
else()
|
|
||||||
message(STATUS "当前使用默认版本的iPhoneSimulator,可以通过设置环境变量IPHONESIMULATOR_VERSION,指定版本")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
project(il2cpp)
|
|
||||||
execute_process(COMMAND sh gen_lump.sh ${PROJECT_BINARY_DIR} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
|
|
||||||
|
|
||||||
add_subdirectory(external)
|
|
||||||
add_subdirectory(objective)
|
|
||||||
|
|
||||||
|
|
||||||
set(IL2CPP_SOURCE_DIR $ENV{HUATUO_IL2CPP_SOURCE_DIR})
|
|
||||||
|
|
||||||
message(STATUS "il2cpp project, binary dir: " ${CMAKE_BINARY_DIR})
|
|
||||||
message(STATUS "il2cpp project, build dir: " ${PROJECT_BINARY_DIR})
|
|
||||||
message(STATUS "il2cpp project, il2cpp source dir: " ${IL2CPP_SOURCE_DIR})
|
|
||||||
|
|
||||||
|
|
||||||
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
|
|
||||||
find_program(CLANG_EXECUTABLE NAMES clang clang-7 clang-8 clang-9 clang-10)
|
|
||||||
if (NOT CLANG_EXECUTABLE)
|
|
||||||
message(FATAL_ERROR "Cannot find any clang executable.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDK_VERSION}.sdk)
|
|
||||||
|
|
||||||
#set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
||||||
set(CMAKE_CXX_COMPILER clang++)
|
|
||||||
set(CMAKE_C_COMPILER clang)
|
|
||||||
#add_compile_options(-x objective-c++)
|
|
||||||
|
|
||||||
# 以下命令为复制的Xcode生成中的命令
|
|
||||||
set(CMAKE_CXX_FLAGS "-target arm64-apple-ios11.0 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu++1z -fmodules -fmodules-prune-interval=86400 -fmodules-prune-after=345600 -fmodules-ignore-macro=IL2CPP_TARGET_IOS=1 -fembed-bitcode -fmodules-ignore-macro=BASELIB_DYNAMICLIBRARY=1 -fmodules-ignore-macro=BASELIB_INLINE_NAMESPACE=il2cpp_baselib -fmodules-ignore-macro=AARCH64 -fmodules-ignore-macro=__aarch64__ -fmodules-ignore-macro=IL2CPP_SUPPORT_THREADS -fmodules-ignore-macro=IL2CPP_THREADS_PTHREAD -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -Wno-trigraphs -fpascal-strings -Os -fno-common -Wno-missing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code -Wquoted-include-in-framework-header -Werror=deprecated-objc-isa-usage -Werror=objc-root-class -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -DIL2CPP_TARGET_IOS=1 -isysroot ${CMAKE_OSX_SYSROOT} -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wunguarded-availability ")
|
|
||||||
|
|
||||||
|
|
||||||
add_definitions(-DIL2CPP_TARGET_IOS=1)
|
|
||||||
add_definitions(-DBASELIB_DYNAMICLIBRARY=1)
|
|
||||||
add_definitions(-DBASELIB_INLINE_NAMESPACE=il2cpp_baselib)
|
|
||||||
add_definitions(-DAARCH64)
|
|
||||||
add_definitions(-D__aarch64__)
|
|
||||||
add_definitions(-DIL2CPP_SUPPORT_THREADS)
|
|
||||||
add_definitions(-DIL2CPP_THREADS_PTHREAD)
|
|
||||||
#add_definitions(-DCMAKE_C_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang)
|
|
||||||
#add_definitions(-DCMAKE_CXX_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++)
|
|
||||||
#add_definitions(-DIL2CPP_TARGET_DARWIN)
|
|
||||||
add_definitions(-DIL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO)
|
|
||||||
|
|
||||||
add_definitions(-MMD)
|
|
||||||
add_definitions(-MT dependencies)
|
|
||||||
|
|
||||||
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/libil2cpp/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/bdwgc/include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Platforms/OSX/Include/)
|
|
||||||
|
|
||||||
# 修改为本机对应SDK路径
|
|
||||||
include_directories(SYSTEM /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/c++/v1)
|
|
||||||
include_directories(SYSTEM /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include)
|
|
||||||
|
|
||||||
aux_source_directory(${PROJECT_BINARY_DIR}/lump_cpp LUMP_SOURCE_LIST)
|
|
||||||
aux_source_directory(${IL2CPP_SOURCE_DIR}/libil2cpp LIBIL2CPP_SOURCE_LIST)
|
|
||||||
|
|
||||||
#find_library(zlib ${PROJECT_SOURCE_DIR}/external)
|
|
||||||
add_library(il2cpp_original STATIC ${LIBIL2CPP_SOURCE_LIST} ${LUMP_SOURCE_LIST})
|
|
||||||
add_dependencies(il2cpp_original external objective)
|
|
||||||
|
|
||||||
add_custom_command(TARGET il2cpp_original
|
|
||||||
POST_BUILD
|
|
||||||
COMMAND xcrun -r libtool -static -o libil2cpp.a libil2cpp_original.a external/libexternal.a objective/libobjective.a
|
|
||||||
COMMENT "post build this is command combine libil2cpp_original.a, libojjective.a and libzlib.a into libil2cpp"
|
|
||||||
)
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
export HUATUO_IL2CPP_SOURCE_DIR=$(pushd ../LocalIl2CppData-OSXEditor/il2cpp > /dev/null && pwd && popd > /dev/null)
|
|
||||||
export IPHONESIMULATOR_VERSION=
|
|
||||||
|
|
||||||
rm -rf build
|
|
||||||
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake -DCMAKE_SYSTEM_PROCESSOR=arm64 -DCMAKE_OSX_ARCHITECTURES=arm64 ..
|
|
||||||
make -j24
|
|
||||||
|
|
||||||
if [ -f "libil2cpp.a" ]
|
|
||||||
then
|
|
||||||
echo 'build succ'
|
|
||||||
else
|
|
||||||
echo "build fail"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# file: external/CMakeList.txt
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET iOS)
|
|
||||||
|
|
||||||
set(IL2CPP_SOURCE_DIR $ENV{HUATUO_IL2CPP_SOURCE_DIR})
|
|
||||||
set(SDK_VERSION $ENV{IPHONESIMULATOR_VERSION})
|
|
||||||
|
|
||||||
message(STATUS "external project, external source dir: " ${IL2CPP_SOURCE_DIR})
|
|
||||||
|
|
||||||
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
|
|
||||||
|
|
||||||
find_program(CLANG_EXECUTABLE NAMES clang clang-7 clang-8 clang-9 clang-10)
|
|
||||||
if (NOT CLANG_EXECUTABLE)
|
|
||||||
message(FATAL_ERROR "Cannot find any clang executable.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDK_VERSION}.sdk)
|
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
||||||
set(CMAKE_C_COMPILER clang)
|
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "-x c -target arm64-apple-ios11.0 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu11 -fmodules -fmodules-prune-interval=86400 -fmodules-prune-after=345600 -fmodules-ignore-macro=IL2CPP_TARGET_IOS=1 -fembed-bitcode -fmodules-ignore-macro=BASELIB_DYNAMICLIBRARY=1 -fmodules-ignore-macro=BASELIB_INLINE_NAMESPACE=il2cpp_baselib -fmodules-ignore-macro=AARCH64 -fmodules-ignore-macro=__aarch64__ -fmodules-ignore-macro=IL2CPP_SUPPORT_THREADS -fmodules-ignore-macro=IL2CPP_THREADS_PTHREAD -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -Wno-trigraphs -fpascal-strings -Os -fno-common -Wno-missing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code -Wquoted-include-in-framework-header -Werror=deprecated-objc-isa-usage -Werror=objc-root-class -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -DIL2CPP_TARGET_IOS=1 -isysroot ${CMAKE_OSX_SYSROOT} -fstrict-aliasing -Wdeprecated-declarations -g -Wno-sign-conversion -Winfinite-recursion -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wno-semicolon-before-method-body -Wunguarded-availability")
|
|
||||||
|
|
||||||
|
|
||||||
add_definitions(-DIL2CPP_TARGET_IOS=1)
|
|
||||||
add_definitions(-DBASELIB_DYNAMICLIBRARY=1)
|
|
||||||
add_definitions(-DBASELIB_INLINE_NAMESPACE=il2cpp_baselib)
|
|
||||||
add_definitions(-DAARCH64)
|
|
||||||
add_definitions(-D__aarch64__)
|
|
||||||
#add_definitions(-D__arm64__)
|
|
||||||
add_definitions(-DIL2CPP_SUPPORT_THREADS)
|
|
||||||
add_definitions(-DIL2CPP_THREADS_PTHREAD)
|
|
||||||
#add_definitions(-DCMAKE_C_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang)
|
|
||||||
#add_definitions(-DCMAKE_CXX_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++)
|
|
||||||
#add_definitions(-DIL2CPP_TARGET_DARWIN)
|
|
||||||
add_definitions(-DIL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO=0)
|
|
||||||
|
|
||||||
add_definitions(-MMD)
|
|
||||||
add_definitions(-MT dependencies)
|
|
||||||
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/bdwgc/include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Platforms/OSX/Include/)
|
|
||||||
|
|
||||||
aux_source_directory(${IL2CPP_SOURCE_DIR}/external/zlib/ ZLIB_C_SOURCE_LIST)
|
|
||||||
add_library(external STATIC ${ZLIB_C_SOURCE_LIST})
|
|
||||||
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
echo '====================================================================='
|
|
||||||
echo 'gen lump'
|
|
||||||
echo '$HUATUO_IL2CPP_SOURCE_DIR='${HUATUO_IL2CPP_SOURCE_DIR} #/Applications/Unity/Unity.app/Contents/il2cpp/
|
|
||||||
|
|
||||||
GEN_SOURCE_DIR=$1
|
|
||||||
BASE_DIR=${HUATUO_IL2CPP_SOURCE_DIR}/libil2cpp
|
|
||||||
echo base dir: ${BASE_DIR}
|
|
||||||
echo " "
|
|
||||||
#BASE_DIR=${HUATUO_IL2CPP_SOURCE_DIR}/libil2cpp
|
|
||||||
function SearchCppFile()
|
|
||||||
{
|
|
||||||
for f in $(ls $1)
|
|
||||||
do
|
|
||||||
SUB_DIR=$1/$f
|
|
||||||
if [ -d ${SUB_DIR} ]; then
|
|
||||||
SearchCppFile ${SUB_DIR}
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
CPP_FILE_NUM=`ls -l $1/ | grep "\.cpp$"|wc -l`
|
|
||||||
if (( ${CPP_FILE_NUM} > 0 ))
|
|
||||||
then
|
|
||||||
for f in $1/*.cpp
|
|
||||||
do
|
|
||||||
echo "#include \""$f"\"" >> ${OUTPUT_FILE_NAME}
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
MM_FILE_NUM=`ls -l $1/ | grep "\.mm$"|wc -l`
|
|
||||||
if (( ${MM_FILE_NUM} > 0 ))
|
|
||||||
then
|
|
||||||
for f in $1/*.mm
|
|
||||||
do
|
|
||||||
echo "#include \""$f"\"" >> ${OBJECTIVE_FILE_NAME}
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
rm -rf "${GEN_SOURCE_DIR}"/lump_cpp
|
|
||||||
rm -rf "${GEN_SOURCE_DIR}"/lump_mm
|
|
||||||
mkdir "${GEN_SOURCE_DIR}"/lump_cpp
|
|
||||||
mkdir "${GEN_SOURCE_DIR}"/lump_mm
|
|
||||||
|
|
||||||
OBJECTIVE_FILE_NAME=${GEN_SOURCE_DIR}/lump_mm/lump_libil2cpp_ojective.mm
|
|
||||||
echo "#include \"${BASE_DIR}/il2cpp-config.h\"" > ${OBJECTIVE_FILE_NAME}
|
|
||||||
echo gen file: ${OBJECTIVE_FILE_NAME}
|
|
||||||
|
|
||||||
for FOLDER in hybridclr vm pch utils vm-utils codegen metadata os debugger mono gc icalls
|
|
||||||
do
|
|
||||||
OUTPUT_FILE_NAME=${GEN_SOURCE_DIR}/lump_cpp/lump_libil2cpp_${FOLDER}.cpp
|
|
||||||
echo "#include \"${BASE_DIR}/il2cpp-config.h\"" > ${OUTPUT_FILE_NAME}
|
|
||||||
if [ $FOLDER = hybridclr ] || [ $FOLDER = vm ]
|
|
||||||
then
|
|
||||||
echo "#include \"${BASE_DIR}/codegen/il2cpp-codegen.h\"" >> ${OUTPUT_FILE_NAME}
|
|
||||||
fi
|
|
||||||
SearchCppFile ${BASE_DIR}/${FOLDER}
|
|
||||||
echo gen file: ${OUTPUT_FILE_NAME}
|
|
||||||
done
|
|
||||||
|
|
||||||
echo gen done.
|
|
||||||
echo '====================================================================='
|
|
||||||
echo " "
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
# file: CMakeList.txt
|
|
||||||
cmake_minimum_required(VERSION 3.0)
|
|
||||||
set(CMAKE_OSX_DEPLOYMENT_TARGET iOS)
|
|
||||||
project(il2cpp)
|
|
||||||
|
|
||||||
set(IL2CPP_SOURCE_DIR $ENV{HUATUO_IL2CPP_SOURCE_DIR})
|
|
||||||
set(SDK_VERSION $ENV{IPHONESIMULATOR_VERSION})
|
|
||||||
|
|
||||||
message(STATUS "objective project, binary dir: " ${PROJECT_BINARY_DIR})
|
|
||||||
message(STATUS "objective project, il2cpp source dir: " ${PROJECT_SOURCE_DIR})
|
|
||||||
|
|
||||||
|
|
||||||
SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS ON)
|
|
||||||
find_program(CLANG_EXECUTABLE NAMES clang clang-7 clang-8 clang-9 clang-10)
|
|
||||||
if (NOT CLANG_EXECUTABLE)
|
|
||||||
message(FATAL_ERROR "Cannot find any clang executable.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator${SDK_VERSION}.sdk)
|
|
||||||
|
|
||||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
|
||||||
set(CMAKE_CXX_COMPILER clang++)
|
|
||||||
set(CMAKE_C_COMPILER clang)
|
|
||||||
#add_compile_options(-x objective-c++)
|
|
||||||
|
|
||||||
# 以下命令为复制的Xcode生成中的命令
|
|
||||||
set(CMAKE_CXX_FLAGS "-target arm64-apple-ios11.0 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -std=gnu++1z -fmodules -fmodules-prune-interval=86400 -fmodules-prune-after=345600 -fmodules-ignore-macro=IL2CPP_TARGET_IOS=1 -fembed-bitcode -fmodules-ignore-macro=BASELIB_DYNAMICLIBRARY=1 -fmodules-ignore-macro=BASELIB_INLINE_NAMESPACE=il2cpp_baselib -fmodules-ignore-macro=AARCH64 -fmodules-ignore-macro=__aarch64__ -fmodules-ignore-macro=IL2CPP_SUPPORT_THREADS -fmodules-ignore-macro=IL2CPP_THREADS_PTHREAD -Wnon-modular-include-in-framework-module -Werror=non-modular-include-in-framework-module -Wno-trigraphs -fpascal-strings -Os -fno-common -Wno-missing-field-initializers -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code -Wquoted-include-in-framework-header -Werror=deprecated-objc-isa-usage -Werror=objc-root-class -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -DIL2CPP_TARGET_IOS=1 -isysroot ${SDK_VERSION} -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -Winfinite-recursion -Wmove -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wrange-loop-analysis -Wno-semicolon-before-method-body -Wunguarded-availability ")
|
|
||||||
|
|
||||||
|
|
||||||
add_definitions(-DIL2CPP_TARGET_IOS=1)
|
|
||||||
add_definitions(-DBASELIB_DYNAMICLIBRARY=1)
|
|
||||||
add_definitions(-DBASELIB_INLINE_NAMESPACE=il2cpp_baselib)
|
|
||||||
add_definitions(-DAARCH64)
|
|
||||||
add_definitions(-D__aarch64__)
|
|
||||||
add_definitions(-DIL2CPP_SUPPORT_THREADS)
|
|
||||||
add_definitions(-DIL2CPP_THREADS_PTHREAD)
|
|
||||||
#add_definitions(-DCMAKE_C_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang)
|
|
||||||
#add_definitions(-DCMAKE_CXX_COMPILER=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++)
|
|
||||||
#add_definitions(-DIL2CPP_TARGET_DARWIN)
|
|
||||||
add_definitions(-DIL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO)
|
|
||||||
|
|
||||||
add_definitions(-MMD)
|
|
||||||
add_definitions(-MT dependencies)
|
|
||||||
|
|
||||||
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/libil2cpp)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/bdwgc/include/)
|
|
||||||
include_directories(${IL2CPP_SOURCE_DIR}/external/baselib/Platforms/OSX/Include/)
|
|
||||||
|
|
||||||
# 修改为本机对应SDK路径
|
|
||||||
include_directories(SYSTEM /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/c++/v1)
|
|
||||||
include_directories(SYSTEM /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include)
|
|
||||||
|
|
||||||
get_filename_component(PARENT_PATH ${PROJECT_BINARY_DIR} PATH)
|
|
||||||
aux_source_directory(${PARENT_PATH}/lump_mm LUMP_SOURCE_LIST)
|
|
||||||
|
|
||||||
#find_library(zlib ${PROJECT_SOURCE_DIR}/external)
|
|
||||||
add_library(objective STATIC ${LUMP_SOURCE_LIST})
|
|
||||||
|
|
||||||
|
|
@ -42,11 +42,11 @@ namespace HybridCLR.Editor.UnityBinFileReader
|
||||||
writer.Write(new EndianBinaryWriter(output));
|
writer.Write(new EndianBinaryWriter(output));
|
||||||
Debug.Log($"patch file:{dataunity3dFile} size:{output.Length}");
|
Debug.Log($"patch file:{dataunity3dFile} size:{output.Length}");
|
||||||
|
|
||||||
string bakFile = dataunity3dFile + ".bak";
|
//string bakFile = dataunity3dFile + ".bak";
|
||||||
if (!File.Exists(bakFile))
|
//if (!File.Exists(bakFile))
|
||||||
{
|
//{
|
||||||
File.Copy(dataunity3dFile, bakFile);
|
// File.Copy(dataunity3dFile, bakFile);
|
||||||
}
|
//}
|
||||||
File.WriteAllBytes(dataunity3dFile, output.ToArray());
|
File.WriteAllBytes(dataunity3dFile, output.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4455f7304f8678f408dd6cf21734f55e
|
guid: 8f2dd29d56a640d4ebd1c2fd374b7638
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 8f2a6638b09b52f4c9dc8906d090b710
|
guid: 13fe0cab0b357464d889de45c8d98850
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
using DotNetDetour;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MonoHook
|
||||||
|
{
|
||||||
|
public unsafe abstract class CodePatcher
|
||||||
|
{
|
||||||
|
public bool isValid { get; protected set; }
|
||||||
|
|
||||||
|
protected void* _pTarget, _pReplace, _pProxy;
|
||||||
|
protected int _jmpCodeSize;
|
||||||
|
protected byte[] _targetHeaderBackup;
|
||||||
|
|
||||||
|
public CodePatcher(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize)
|
||||||
|
{
|
||||||
|
_pTarget = target.ToPointer();
|
||||||
|
_pReplace = replace.ToPointer();
|
||||||
|
_pProxy = proxy.ToPointer();
|
||||||
|
_jmpCodeSize = jmpCodeSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyPatch()
|
||||||
|
{
|
||||||
|
BackupHeader();
|
||||||
|
EnableAddrModifiable();
|
||||||
|
PatchTargetMethod();
|
||||||
|
PatchProxyMethod();
|
||||||
|
FlushICache();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemovePatch()
|
||||||
|
{
|
||||||
|
if (_targetHeaderBackup == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EnableAddrModifiable();
|
||||||
|
RestoreHeader();
|
||||||
|
FlushICache();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void BackupHeader()
|
||||||
|
{
|
||||||
|
if (_targetHeaderBackup != null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint requireSize = LDasm.SizeofMinNumByte(_pTarget, _jmpCodeSize);
|
||||||
|
_targetHeaderBackup = new byte[requireSize];
|
||||||
|
|
||||||
|
fixed (void* ptr = _targetHeaderBackup)
|
||||||
|
HookUtils.MemCpy(ptr, _pTarget, _targetHeaderBackup.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RestoreHeader()
|
||||||
|
{
|
||||||
|
if (_targetHeaderBackup == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
HookUtils.MemCpy_Jit(_pTarget, _targetHeaderBackup);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void PatchTargetMethod()
|
||||||
|
{
|
||||||
|
byte[] buff = GenJmpCode(_pTarget, _pReplace);
|
||||||
|
HookUtils.MemCpy_Jit(_pTarget, buff);
|
||||||
|
}
|
||||||
|
protected void PatchProxyMethod()
|
||||||
|
{
|
||||||
|
if (_pProxy == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// copy target's code to proxy
|
||||||
|
HookUtils.MemCpy_Jit(_pProxy, _targetHeaderBackup);
|
||||||
|
|
||||||
|
// jmp to target's new position
|
||||||
|
long jmpFrom = (long)_pProxy + _targetHeaderBackup.Length;
|
||||||
|
long jmpTo = (long)_pTarget + _targetHeaderBackup.Length;
|
||||||
|
|
||||||
|
byte[] buff = GenJmpCode((void*)jmpFrom, (void*)jmpTo);
|
||||||
|
HookUtils.MemCpy_Jit((void*)jmpFrom, buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void FlushICache()
|
||||||
|
{
|
||||||
|
HookUtils.FlushICache(_pTarget, _targetHeaderBackup.Length);
|
||||||
|
HookUtils.FlushICache(_pProxy, _targetHeaderBackup.Length * 2);
|
||||||
|
}
|
||||||
|
protected abstract byte[] GenJmpCode(void* jmpFrom, void* jmpTo);
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
protected string PrintAddrs()
|
||||||
|
{
|
||||||
|
if (IntPtr.Size == 4)
|
||||||
|
return $"target:0x{(uint)_pTarget:x}, replace:0x{(uint)_pReplace:x}, proxy:0x{(uint)_pProxy:x}";
|
||||||
|
else
|
||||||
|
return $"target:0x{(ulong)_pTarget:x}, replace:0x{(ulong)_pReplace:x}, proxy:0x{(ulong)_pProxy:x}";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private void EnableAddrModifiable()
|
||||||
|
{
|
||||||
|
HookUtils.SetAddrFlagsToRWX(new IntPtr(_pTarget), _targetHeaderBackup.Length);
|
||||||
|
HookUtils.SetAddrFlagsToRWX(new IntPtr(_pProxy), _targetHeaderBackup.Length + _jmpCodeSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe class CodePatcher_x86 : CodePatcher
|
||||||
|
{
|
||||||
|
protected static readonly byte[] s_jmpCode = new byte[] // 5 bytes
|
||||||
|
{
|
||||||
|
0xE9, 0x00, 0x00, 0x00, 0x00, // jmp $val ; $val = $dst - $src - 5
|
||||||
|
};
|
||||||
|
|
||||||
|
public CodePatcher_x86(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
|
||||||
|
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[s_jmpCode.Length];
|
||||||
|
int val = (int)jmpTo - (int)jmpFrom - 5;
|
||||||
|
|
||||||
|
fixed(void * p = &ret[0])
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*)p;
|
||||||
|
*ptr = 0xE9;
|
||||||
|
int* pOffset = (int*)(ptr + 1);
|
||||||
|
*pOffset = val;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// x64下2G 内的跳转
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class CodePatcher_x64_near : CodePatcher_x86 // x64_near pathcer code is same to x86
|
||||||
|
{
|
||||||
|
public CodePatcher_x64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// x64下距离超过2G的跳转
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class CodePatcher_x64_far : CodePatcher
|
||||||
|
{
|
||||||
|
protected static readonly byte[] s_jmpCode = new byte[] // 12 bytes
|
||||||
|
{
|
||||||
|
// 由于 rax 会被函数作为返回值修改,并且不会被做为参数使用,因此修改是安全的
|
||||||
|
0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, <jmpTo>
|
||||||
|
0x50, // push rax
|
||||||
|
0xC3 // ret
|
||||||
|
};
|
||||||
|
|
||||||
|
//protected static readonly byte[] s_jmpCode2 = new byte[] // 14 bytes
|
||||||
|
//{
|
||||||
|
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <jmpTo>
|
||||||
|
// 0xFF, 0x25, 0xF2, 0xFF, 0xFF, 0xFF // jmp [rip - 0xe]
|
||||||
|
//};
|
||||||
|
|
||||||
|
public CodePatcher_x64_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length) { }
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[s_jmpCode.Length];
|
||||||
|
|
||||||
|
fixed (void* p = &ret[0])
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*)p;
|
||||||
|
*ptr++ = 0x48;
|
||||||
|
*ptr++ = 0xB8;
|
||||||
|
*(long*)ptr = (long)jmpTo;
|
||||||
|
ptr += 8;
|
||||||
|
*ptr++ = 0x50;
|
||||||
|
*ptr++ = 0xC3;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe class CodePatcher_arm32_near : CodePatcher
|
||||||
|
{
|
||||||
|
private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
|
||||||
|
{
|
||||||
|
0x00, 0x00, 0x00, 0xEA, // B $val ; $val = (($dst - $src) / 4 - 2) & 0x1FFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
public CodePatcher_arm32_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
|
||||||
|
{
|
||||||
|
if (Math.Abs((long)target - (long)replace) >= ((1 << 25) - 1))
|
||||||
|
throw new ArgumentException("address offset of target and replace must less than ((1 << 25) - 1)");
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
Debug.Log($"CodePatcher_arm32_near: {PrintAddrs()}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[s_jmpCode.Length];
|
||||||
|
int val = ((int)jmpTo - (int)jmpFrom) / 4 - 2;
|
||||||
|
|
||||||
|
fixed (void* p = &ret[0])
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*)p;
|
||||||
|
*ptr++ = (byte)val;
|
||||||
|
*ptr++ = (byte)(val >> 8);
|
||||||
|
*ptr++ = (byte)(val >> 16);
|
||||||
|
*ptr++ = 0xEA;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe class CodePatcher_arm32_far : CodePatcher
|
||||||
|
{
|
||||||
|
private static readonly byte[] s_jmpCode = new byte[] // 8 bytes
|
||||||
|
{
|
||||||
|
0x04, 0xF0, 0x1F, 0xE5, // LDR PC, [PC, #-4]
|
||||||
|
0x00, 0x00, 0x00, 0x00, // $val
|
||||||
|
};
|
||||||
|
|
||||||
|
public CodePatcher_arm32_far(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
|
||||||
|
{
|
||||||
|
if (Math.Abs((long)target - (long)replace) < ((1 << 25) - 1))
|
||||||
|
throw new ArgumentException("address offset of target and replace must larger than ((1 << 25) - 1), please use InstructionModifier_arm32_near instead");
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
Debug.Log($"CodePatcher_arm32_far: {PrintAddrs()}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[s_jmpCode.Length];
|
||||||
|
|
||||||
|
fixed (void* p = &ret[0])
|
||||||
|
{
|
||||||
|
uint* ptr = (uint*)p;
|
||||||
|
*ptr++ = 0xE51FF004;
|
||||||
|
*ptr = (uint)jmpTo;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// arm64 下 ±128MB 范围内的跳转
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class CodePatcher_arm64_near : CodePatcher
|
||||||
|
{
|
||||||
|
private static readonly byte[] s_jmpCode = new byte[] // 4 bytes
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* from 0x14 to 0x17 is B opcode
|
||||||
|
* offset bits is 26
|
||||||
|
* https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/B--Branch-
|
||||||
|
*/
|
||||||
|
0x00, 0x00, 0x00, 0x14, // B $val ; $val = (($dst - $src)/4) & 7FFFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
public CodePatcher_arm64_near(IntPtr target, IntPtr replace, IntPtr proxy) : base(target, replace, proxy, s_jmpCode.Length)
|
||||||
|
{
|
||||||
|
if (Math.Abs((long)target - (long)replace) >= ((1 << 26) - 1) * 4)
|
||||||
|
throw new ArgumentException("address offset of target and replace must less than (1 << 26) - 1) * 4");
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
Debug.Log($"CodePatcher_arm64: {PrintAddrs()}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
byte[] ret = new byte[s_jmpCode.Length];
|
||||||
|
int val = (int)((long)jmpTo - (long)jmpFrom) / 4;
|
||||||
|
|
||||||
|
fixed (void* p = &ret[0])
|
||||||
|
{
|
||||||
|
byte* ptr = (byte*)p;
|
||||||
|
*ptr++ = (byte)val;
|
||||||
|
*ptr++ = (byte)(val >> 8);
|
||||||
|
*ptr++ = (byte)(val >> 16);
|
||||||
|
|
||||||
|
byte last = (byte)(val >> 24);
|
||||||
|
last &= 0b11;
|
||||||
|
last |= 0x14;
|
||||||
|
|
||||||
|
*ptr = last;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// arm64 远距离跳转
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class CodePatcher_arm64_far : CodePatcher
|
||||||
|
{
|
||||||
|
private static readonly byte[] s_jmpCode = new byte[] // 20 bytes(字节数过多,太危险了,不建议使用)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ADR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/ADR--Form-PC-relative-address-
|
||||||
|
* BR: https://developer.arm.com/documentation/ddi0596/2021-09/Base-Instructions/BR--Branch-to-Register-
|
||||||
|
*/
|
||||||
|
0x6A, 0x00, 0x00, 0x10, // ADR X10, #C
|
||||||
|
0x4A, 0x01, 0x40, 0xF9, // LDR X10, [X10,#0]
|
||||||
|
0x40, 0x01, 0x1F, 0xD6, // BR X10
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // $dst
|
||||||
|
};
|
||||||
|
|
||||||
|
public CodePatcher_arm64_far(IntPtr target, IntPtr replace, IntPtr proxy, int jmpCodeSize) : base(target, replace, proxy, jmpCodeSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override unsafe byte[] GenJmpCode(void* jmpFrom, void* jmpTo)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: a22846b73022cb2458d1c40549ab6877
|
guid: 97cc0d26f72fc4148b8370b2252d1585
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace MonoHook
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hook 池,防止重复 Hook
|
||||||
|
/// </summary>
|
||||||
|
public static class HookPool
|
||||||
|
{
|
||||||
|
private static Dictionary<MethodBase, MethodHook> _hooks = new Dictionary<MethodBase, MethodHook>();
|
||||||
|
|
||||||
|
public static void AddHook(MethodBase method, MethodHook hook)
|
||||||
|
{
|
||||||
|
MethodHook preHook;
|
||||||
|
if (_hooks.TryGetValue(method, out preHook))
|
||||||
|
{
|
||||||
|
preHook.Uninstall();
|
||||||
|
_hooks[method] = hook;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_hooks.Add(method, hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodHook GetHook(MethodBase method)
|
||||||
|
{
|
||||||
|
if (method == null) return null;
|
||||||
|
|
||||||
|
MethodHook hook;
|
||||||
|
if (_hooks.TryGetValue(method, out hook))
|
||||||
|
return hook;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RemoveHooker(MethodBase method)
|
||||||
|
{
|
||||||
|
if (method == null) return;
|
||||||
|
|
||||||
|
_hooks.Remove(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UninstallAll()
|
||||||
|
{
|
||||||
|
var list = _hooks.Values.ToList();
|
||||||
|
foreach (var hook in list)
|
||||||
|
hook.Uninstall();
|
||||||
|
|
||||||
|
_hooks.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UninstallByTag(string tag)
|
||||||
|
{
|
||||||
|
var list = _hooks.Values.ToList();
|
||||||
|
foreach (var hook in list)
|
||||||
|
{
|
||||||
|
if(hook.tag == tag)
|
||||||
|
hook.Uninstall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<MethodHook> GetAllHooks()
|
||||||
|
{
|
||||||
|
return _hooks.Values.ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b63c5bf995a6d624dbd10d9df6cb6a7a
|
guid: 6b7421e47f0ae1e4ebb72bf18d1d7d48
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -0,0 +1,272 @@
|
||||||
|
#if !(UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MonoHook
|
||||||
|
{
|
||||||
|
public static unsafe class HookUtils
|
||||||
|
{
|
||||||
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||||
|
delegate void DelegateFlushICache(void* code, int size); // delegate * unmanaged[Cdecl] <void, byte, uint> native_flush_cache_fun_ptr; // unsupported at C# 8.0
|
||||||
|
|
||||||
|
static DelegateFlushICache flush_icache;
|
||||||
|
private static readonly long _Pagesize;
|
||||||
|
|
||||||
|
static HookUtils()
|
||||||
|
{
|
||||||
|
PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
|
||||||
|
if (p_SystemPageSize == null)
|
||||||
|
throw new NotSupportedException("Unsupported runtime");
|
||||||
|
_Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
|
||||||
|
SetupFlushICacheFunc();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MemCpy(void* pDst, void* pSrc, int len)
|
||||||
|
{
|
||||||
|
byte* pDst_ = (byte*)pDst;
|
||||||
|
byte* pSrc_ = (byte*)pSrc;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
*pDst_++ = *pSrc_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MemCpy_Jit(void* pDst, byte[] src)
|
||||||
|
{
|
||||||
|
fixed (void* p = &src[0])
|
||||||
|
{
|
||||||
|
MemCpy(pDst, p, src.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// set flags of address to `read write execute`
|
||||||
|
/// </summary>
|
||||||
|
public static void SetAddrFlagsToRWX(IntPtr ptr, int size)
|
||||||
|
{
|
||||||
|
if (ptr == IntPtr.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
||||||
|
uint oldProtect;
|
||||||
|
bool ret = VirtualProtect(ptr, (uint)size, Protection.PAGE_EXECUTE_READWRITE, out oldProtect);
|
||||||
|
UnityEngine.Debug.Assert(ret);
|
||||||
|
#else
|
||||||
|
SetMemPerms(ptr,(ulong)size,MmapProts.PROT_READ | MmapProts.PROT_WRITE | MmapProts.PROT_EXEC);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FlushICache(void* code, int size)
|
||||||
|
{
|
||||||
|
if (code == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flush_icache?.Invoke(code, size);
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
Debug.Log($"flush icache at 0x{(IntPtr.Size == 4 ? (uint)code : (ulong)code):x}, size:{size}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyValuePair<long, long> GetPageAlignedAddr(long code, int size)
|
||||||
|
{
|
||||||
|
long pagesize = _Pagesize;
|
||||||
|
long startPage = (code) & ~(pagesize - 1);
|
||||||
|
long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
|
||||||
|
return new KeyValuePair<long, long>(startPage, endPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const int PRINT_SPLIT = 4;
|
||||||
|
const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
|
||||||
|
public static string HexToString(void* ptr, int size, int offset = 0)
|
||||||
|
{
|
||||||
|
Func<IntPtr, string> formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
|
||||||
|
|
||||||
|
byte* addr = (byte*)ptr;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(1024);
|
||||||
|
sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
|
||||||
|
|
||||||
|
addr += offset;
|
||||||
|
size += Math.Abs(offset);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
|
||||||
|
for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
|
||||||
|
{
|
||||||
|
if (count >= size)
|
||||||
|
goto END;
|
||||||
|
|
||||||
|
sb.Append($"{*(addr + count):x2}");
|
||||||
|
if (i % PRINT_SPLIT == 0)
|
||||||
|
sb.Append(" ");
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END:;
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetupFlushICacheFunc()
|
||||||
|
{
|
||||||
|
string processorType = SystemInfo.processorType.ToLowerInvariant();
|
||||||
|
if (processorType.Contains("intel") || processorType.Contains("amd"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IntPtr.Size == 4)
|
||||||
|
{
|
||||||
|
// never release, so save GCHandle is unnecessary
|
||||||
|
s_ptr_flush_icache_arm32 = GCHandle.Alloc(s_flush_icache_arm32, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
|
||||||
|
SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm32), s_flush_icache_arm32.Length);
|
||||||
|
flush_icache = Marshal.GetDelegateForFunctionPointer<DelegateFlushICache>(new IntPtr(s_ptr_flush_icache_arm32));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_ptr_flush_icache_arm64 = GCHandle.Alloc(s_flush_icache_arm64, GCHandleType.Pinned).AddrOfPinnedObject().ToPointer();
|
||||||
|
SetAddrFlagsToRWX(new IntPtr(s_ptr_flush_icache_arm64), s_flush_icache_arm64.Length);
|
||||||
|
flush_icache = Marshal.GetDelegateForFunctionPointer<DelegateFlushICache>(new IntPtr(s_ptr_flush_icache_arm64));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
Debug.Log($"flush_icache delegate is {((flush_icache != null) ? "not " : "")}null");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void* s_ptr_flush_icache_arm32, s_ptr_flush_icache_arm64;
|
||||||
|
private static byte[] s_flush_icache_arm32 = new byte[]
|
||||||
|
{
|
||||||
|
// void cdecl mono_arch_flush_icache (guint8 *code, gint size)
|
||||||
|
0x00, 0x48, 0x2D, 0xE9, // PUSH {R11,LR}
|
||||||
|
0x0D, 0xB0, 0xA0, 0xE1, // MOV R11, SP
|
||||||
|
0x08, 0xD0, 0x4D, 0xE2, // SUB SP, SP, #8
|
||||||
|
0x04, 0x00, 0x8D, 0xE5, // STR R0, [SP,#8+var_4]
|
||||||
|
0x00, 0x10, 0x8D, 0xE5, // STR R1, [SP,#8+var_8]
|
||||||
|
0x04, 0x00, 0x9D, 0xE5, // LDR R0, [SP,#8+var_4]
|
||||||
|
0x04, 0x10, 0x9D, 0xE5, // LDR R1, [SP,#8+var_4]
|
||||||
|
0x00, 0x20, 0x9D, 0xE5, // LDR R2, [SP,#8+var_8]
|
||||||
|
0x02, 0x10, 0x81, 0xE0, // ADD R1, R1, R2
|
||||||
|
0x01, 0x00, 0x00, 0xEB, // BL __clear_cache
|
||||||
|
0x0B, 0xD0, 0xA0, 0xE1, // MOV SP, R11
|
||||||
|
0x00, 0x88, 0xBD, 0xE8, // POP {R11,PC}
|
||||||
|
|
||||||
|
// __clear_cache ; CODE XREF: j___clear_cache+8↑j
|
||||||
|
0x80, 0x00, 0x2D, 0xE9, // PUSH { R7 }
|
||||||
|
0x02, 0x70, 0x00, 0xE3, 0x0F, 0x70, 0x40, 0xE3, // MOV R7, #0xF0002
|
||||||
|
0x00, 0x20, 0xA0, 0xE3, // MOV R2, #0
|
||||||
|
0x00, 0x00, 0x00, 0xEF, // SVC 0
|
||||||
|
0x80, 0x00, 0xBD, 0xE8, // POP {R7}
|
||||||
|
0x1E, 0xFF, 0x2F, 0xE1, // BX LR
|
||||||
|
};
|
||||||
|
|
||||||
|
private static byte[] s_flush_icache_arm64 = new byte[] // X0: code, W1: size
|
||||||
|
{
|
||||||
|
// void cdecl mono_arch_flush_icache (guint8 *code, gint size)
|
||||||
|
0xFF, 0xC3, 0x00, 0xD1, // SUB SP, SP, #0x30
|
||||||
|
0xE8, 0x03, 0x7E, 0xB2, // MOV X8, #4
|
||||||
|
0xE0, 0x17, 0x00, 0xF9, // STR X0, [SP,#0x30+var_8]
|
||||||
|
0xE1, 0x27, 0x00, 0xB9, // STR W1, [SP,#0x30+var_C]
|
||||||
|
0xE0, 0x17, 0x40, 0xF9, // LDR X0, [SP,#0x30+var_8]
|
||||||
|
0xE9, 0x27, 0x80, 0xB9, // LDRSW X9, [SP,#0x30+var_C]
|
||||||
|
0x09, 0x00, 0x09, 0x8B, // ADD X9, X0, X9
|
||||||
|
0xE9, 0x0F, 0x00, 0xF9, // STR X9, [SP,#0x30+var_18]
|
||||||
|
0xE8, 0x07, 0x00, 0xF9, // STR X8, [SP,#0x30+var_28]
|
||||||
|
0xE8, 0x03, 0x00, 0xF9, // STR X8, [SP,#0x30+var_30]
|
||||||
|
0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
|
||||||
|
0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
|
||||||
|
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
|
||||||
|
|
||||||
|
// loc_590 ; CODE XREF: mono_arch_flush_icache(uchar*, int)+58↓j
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
|
||||||
|
0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
|
||||||
|
0xE2, 0x00, 0x00, 0x54, // B.CS loc_5B8
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0x28, 0x7E, 0x0B, 0xD5, // SYS #3, c7, c14, #1, X8
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
|
||||||
|
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
|
||||||
|
0xF7, 0xFF, 0xFF, 0x17, // B loc_590
|
||||||
|
// ; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// loc_5B8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+40↑j
|
||||||
|
0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
|
||||||
|
0xE8, 0x17, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_8]
|
||||||
|
0x08, 0xF5, 0x7E, 0x92, // AND X8, X8, #0xFFFFFFFFFFFFFFFC
|
||||||
|
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
|
||||||
|
|
||||||
|
// loc_5C8 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+90↓j
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0xE9, 0x0F, 0x40, 0xF9, // LDR X9, [SP,#0x30+var_18]
|
||||||
|
0x1F, 0x01, 0x09, 0xEB, // CMP X8, X9
|
||||||
|
0xE2, 0x00, 0x00, 0x54, // B.CS loc_5F0
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0x28, 0x75, 0x0B, 0xD5, // SYS #3, c7, c5, #1, X8
|
||||||
|
0xE8, 0x0B, 0x40, 0xF9, // LDR X8, [SP,#0x30+var_20]
|
||||||
|
0x08, 0x11, 0x00, 0x91, // ADD X8, X8, #4
|
||||||
|
0xE8, 0x0B, 0x00, 0xF9, // STR X8, [SP,#0x30+var_20]
|
||||||
|
0xF7, 0xFF, 0xFF, 0x17, // B loc_5C8
|
||||||
|
// ; ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// loc_5F0 ; CODE XREF: mono_arch_flush_icache(uchar *, int)+78↑j
|
||||||
|
0x9F, 0x3B, 0x03, 0xD5, // DSB ISH
|
||||||
|
0xDF, 0x3F, 0x03, 0xD5, // ISB
|
||||||
|
0xFF, 0xC3, 0x00, 0x91, // ADD SP, SP, #0x30 ; '0'
|
||||||
|
0xC0, 0x03, 0x5F, 0xD6, // RET
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
||||||
|
[Flags]
|
||||||
|
public enum Protection
|
||||||
|
{
|
||||||
|
PAGE_NOACCESS = 0x01,
|
||||||
|
PAGE_READONLY = 0x02,
|
||||||
|
PAGE_READWRITE = 0x04,
|
||||||
|
PAGE_WRITECOPY = 0x08,
|
||||||
|
PAGE_EXECUTE = 0x10,
|
||||||
|
PAGE_EXECUTE_READ = 0x20,
|
||||||
|
PAGE_EXECUTE_READWRITE = 0x40,
|
||||||
|
PAGE_EXECUTE_WRITECOPY = 0x80,
|
||||||
|
PAGE_GUARD = 0x100,
|
||||||
|
PAGE_NOCACHE = 0x200,
|
||||||
|
PAGE_WRITECOMBINE = 0x400
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern bool VirtualProtect(IntPtr lpAddress, uint dwSize, Protection flNewProtect, out uint lpflOldProtect);
|
||||||
|
|
||||||
|
#else
|
||||||
|
[Flags]
|
||||||
|
public enum MmapProts : int {
|
||||||
|
PROT_READ = 0x1,
|
||||||
|
PROT_WRITE = 0x2,
|
||||||
|
PROT_EXEC = 0x4,
|
||||||
|
PROT_NONE = 0x0,
|
||||||
|
PROT_GROWSDOWN = 0x01000000,
|
||||||
|
PROT_GROWSUP = 0x02000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("libc", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern int mprotect(IntPtr start, IntPtr len, MmapProts prot);
|
||||||
|
|
||||||
|
public static unsafe void SetMemPerms(IntPtr start, ulong len, MmapProts prot) {
|
||||||
|
var requiredAddr = GetPageAlignedAddr(start.ToInt64(), (int)len);
|
||||||
|
long startPage = requiredAddr.Key;
|
||||||
|
long endPage = requiredAddr.Value;
|
||||||
|
|
||||||
|
if (mprotect((IntPtr) startPage, (IntPtr) (endPage - startPage), prot) != 0)
|
||||||
|
throw new Exception($"mprotect with prot:{prot} fail!");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: fe1634f74b7ca2e42bd07233b451cd94
|
guid: e84139b42a6164e4c93ce4df1be6dcfb
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -0,0 +1,116 @@
|
||||||
|
#if (UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX)
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MonoHook
|
||||||
|
{
|
||||||
|
public static unsafe class HookUtils
|
||||||
|
{
|
||||||
|
static bool jit_write_protect_supported;
|
||||||
|
private static readonly long _Pagesize;
|
||||||
|
|
||||||
|
|
||||||
|
static HookUtils()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
jit_write_protect_supported = pthread_jit_write_protect_supported_np() != 0;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
PropertyInfo p_SystemPageSize = typeof(Environment).GetProperty("SystemPageSize");
|
||||||
|
if (p_SystemPageSize == null)
|
||||||
|
throw new NotSupportedException("Unsupported runtime");
|
||||||
|
_Pagesize = (int)p_SystemPageSize.GetValue(null, new object[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MemCpy(void* pDst, void* pSrc, int len)
|
||||||
|
{
|
||||||
|
byte* pDst_ = (byte*)pDst;
|
||||||
|
byte* pSrc_ = (byte*)pSrc;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
*pDst_++ = *pSrc_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void MemCpy_Jit(void* pDst, byte[] src)
|
||||||
|
{
|
||||||
|
if (!jit_write_protect_supported)
|
||||||
|
{
|
||||||
|
fixed(void * pSrc = &src[0])
|
||||||
|
{
|
||||||
|
MemCpy(pDst, pSrc, src.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed(void * p = &src[0])
|
||||||
|
{
|
||||||
|
memcpy_jit(new IntPtr(pDst), new IntPtr(p), src.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// set flags of address to `read write execute`
|
||||||
|
/// </summary>
|
||||||
|
public static void SetAddrFlagsToRWX(IntPtr ptr, int size) { }
|
||||||
|
|
||||||
|
public static void FlushICache(void* code, int size) { }
|
||||||
|
|
||||||
|
public static KeyValuePair<long, long> GetPageAlignedAddr(long code, int size)
|
||||||
|
{
|
||||||
|
long pagesize = _Pagesize;
|
||||||
|
long startPage = (code) & ~(pagesize - 1);
|
||||||
|
long endPage = (code + size + pagesize - 1) & ~(pagesize - 1);
|
||||||
|
return new KeyValuePair<long, long>(startPage, endPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const int PRINT_SPLIT = 4;
|
||||||
|
const int PRINT_COL_SIZE = PRINT_SPLIT * 4;
|
||||||
|
public static string HexToString(void* ptr, int size, int offset = 0)
|
||||||
|
{
|
||||||
|
Func<IntPtr, string> formatAddr = (IntPtr addr__) => IntPtr.Size == 4 ? $"0x{(uint)addr__:x}" : $"0x{(ulong)addr__:x}";
|
||||||
|
|
||||||
|
byte* addr = (byte*)ptr;
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder(1024);
|
||||||
|
sb.AppendLine($"addr:{formatAddr(new IntPtr(addr))}");
|
||||||
|
|
||||||
|
addr += offset;
|
||||||
|
size += Math.Abs(offset);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
sb.Append($"\r\n{formatAddr(new IntPtr(addr + count))}: ");
|
||||||
|
for (int i = 1; i < PRINT_COL_SIZE + 1; i++)
|
||||||
|
{
|
||||||
|
if (count >= size)
|
||||||
|
goto END;
|
||||||
|
|
||||||
|
sb.Append($"{*(addr + count):x2}");
|
||||||
|
if (i % PRINT_SPLIT == 0)
|
||||||
|
sb.Append(" ");
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END:;
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("pthread", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern int pthread_jit_write_protect_supported_np();
|
||||||
|
|
||||||
|
[DllImport("libMonoHookUtils_OSX", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
private static extern IntPtr memcpy_jit(IntPtr dst, IntPtr src, int len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1eb9e19189731a344aad024a43e795bc
|
guid: efda6e010e5c6594081c4a62861d469f
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: d104ab5da8136154899a40116dc88731
|
guid: d796fc01daee1964586621890988a5ae
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using MonoHook;
|
||||||
|
using HybridCLR.Editor.BuildProcessors;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace HybridCLR.MonoHook
|
||||||
|
{
|
||||||
|
#if UNITY_2021_1_OR_NEWER && !UNITY_2023_1_OR_NEWER
|
||||||
|
[InitializeOnLoad]
|
||||||
|
public class CopyStrippedAOTAssembliesHook
|
||||||
|
{
|
||||||
|
private static MethodHook _hook;
|
||||||
|
|
||||||
|
static CopyStrippedAOTAssembliesHook()
|
||||||
|
{
|
||||||
|
if (_hook == null)
|
||||||
|
{
|
||||||
|
Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.AssemblyStripper");
|
||||||
|
MethodInfo miTarget = type.GetMethod("StripAssembliesTo", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
|
||||||
|
MethodInfo miReplacement = new StripAssembliesDel(OverrideStripAssembliesTo).Method;
|
||||||
|
MethodInfo miProxy = new StripAssembliesDel(StripAssembliesToProxy).Method;
|
||||||
|
|
||||||
|
_hook = new MethodHook(miTarget, miReplacement, miProxy);
|
||||||
|
_hook.Install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate bool StripAssembliesDel(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation);
|
||||||
|
|
||||||
|
private static bool OverrideStripAssembliesTo(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation)
|
||||||
|
{
|
||||||
|
bool result = StripAssembliesToProxy(outputFolder, out output, out error, linkXmlFiles, runInformation);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UnityEngine.Debug.Log($"== StripAssembliesTo outputDir:{outputFolder}");
|
||||||
|
string outputStrippedDir = HybridCLR.Editor.SettingsUtil.GetAssembliesPostIl2CppStripDir(EditorUserBuildSettings.activeBuildTarget);
|
||||||
|
Directory.CreateDirectory(outputStrippedDir);
|
||||||
|
foreach (var aotDll in Directory.GetFiles(outputFolder, "*.dll"))
|
||||||
|
{
|
||||||
|
string dstFile = $"{outputStrippedDir}/{Path.GetFileName(aotDll)}";
|
||||||
|
Debug.Log($"[RunAssemblyStripper] copy aot dll {aotDll} -> {dstFile}");
|
||||||
|
File.Copy(aotDll, dstFile, true);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
|
private static bool StripAssembliesToProxy(string outputFolder, out string output, out string error, IEnumerable<string> linkXmlFiles, object runInformation)
|
||||||
|
{
|
||||||
|
Debug.LogError("== StripAssembliesToProxy ==");
|
||||||
|
output = "";
|
||||||
|
error = "";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cf42c4f20b8a1b94baa04a1a5c6b8beb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using MonoHook;
|
||||||
|
using HybridCLR.Editor.BuildProcessors;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace HybridCLR.MonoHook
|
||||||
|
{
|
||||||
|
#if UNITY_2022 || UNITY_2023_1_OR_NEWER
|
||||||
|
[InitializeOnLoad]
|
||||||
|
public class GetIl2CppFolderHook
|
||||||
|
{
|
||||||
|
private static MethodHook _hook;
|
||||||
|
|
||||||
|
static GetIl2CppFolderHook()
|
||||||
|
{
|
||||||
|
if (_hook == null)
|
||||||
|
{
|
||||||
|
Type type = typeof(UnityEditor.EditorApplication).Assembly.GetType("UnityEditorInternal.IL2CPPUtils");
|
||||||
|
MethodInfo miTarget = type.GetMethod("GetIl2CppFolder", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null,
|
||||||
|
new Type[] { typeof(bool).MakeByRefType() }, null);
|
||||||
|
|
||||||
|
MethodInfo miReplacement = new StripAssembliesDel(OverrideMethod).Method;
|
||||||
|
MethodInfo miProxy = new StripAssembliesDel(PlaceHolderMethod).Method;
|
||||||
|
|
||||||
|
_hook = new MethodHook(miTarget, miReplacement, miProxy);
|
||||||
|
_hook.Install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private delegate string StripAssembliesDel(out bool isDevelopmentLocation);
|
||||||
|
|
||||||
|
private static string OverrideMethod(out bool isDevelopmentLocation)
|
||||||
|
{
|
||||||
|
//Debug.Log("[GetIl2CppFolderHook] OverrideMethod");
|
||||||
|
string result = PlaceHolderMethod(out isDevelopmentLocation);
|
||||||
|
isDevelopmentLocation = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
|
private static string PlaceHolderMethod(out bool isDevelopmentLocation)
|
||||||
|
{
|
||||||
|
Debug.LogError("[GetIl2CppFolderHook] PlaceHolderMethod");
|
||||||
|
isDevelopmentLocation = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 96c2bc28db69e1644892219abef3d4b5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using MonoHook;
|
||||||
|
using HybridCLR.Editor.BuildProcessors;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace HybridCLR.MonoHook
|
||||||
|
{
|
||||||
|
#if UNITY_2021_1_OR_NEWER && (UNITY_WEBGL || UNITY_WEIXINMINIGAME)
|
||||||
|
[InitializeOnLoad]
|
||||||
|
public class PatchScriptingAssembliesJsonHook
|
||||||
|
{
|
||||||
|
private static MethodHook _hook;
|
||||||
|
|
||||||
|
static PatchScriptingAssembliesJsonHook()
|
||||||
|
{
|
||||||
|
if (_hook == null)
|
||||||
|
{
|
||||||
|
Type type = typeof(UnityEditor.EditorApplication);
|
||||||
|
MethodInfo miTarget = type.GetMethod("BuildMainWindowTitle", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
MethodInfo miReplacement = new Func<string>(BuildMainWindowTitle).Method;
|
||||||
|
MethodInfo miProxy = new Func<string>(BuildMainWindowTitleProxy).Method;
|
||||||
|
|
||||||
|
_hook = new MethodHook(miTarget, miReplacement, miProxy);
|
||||||
|
_hook.Install();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildMainWindowTitle()
|
||||||
|
{
|
||||||
|
var cacheDir = $"{Application.dataPath}/../Library/PlayerDataCache";
|
||||||
|
if (Directory.Exists(cacheDir))
|
||||||
|
{
|
||||||
|
foreach (var tempJsonPath in Directory.GetDirectories(cacheDir, "*", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
string dirName = Path.GetFileName(tempJsonPath);
|
||||||
|
#if UNITY_WEIXINMINIGAME
|
||||||
|
if (!dirName.Contains("WeixinMiniGame"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!dirName.Contains("WebGL"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
var patcher = new PatchScriptingAssemblyList();
|
||||||
|
patcher.PathScriptingAssembilesFile(tempJsonPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string newTitle = BuildMainWindowTitleProxy();
|
||||||
|
return newTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoOptimization)]
|
||||||
|
private static string BuildMainWindowTitleProxy()
|
||||||
|
{
|
||||||
|
// 为满足MonoHook要求的最小代码长度而特地加入的无用填充代码,
|
||||||
|
UnityEngine.Debug.Log(12345.ToString());
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cc89a9041ab48ac41975fbd1e00b9b98
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,903 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DotNetDetour
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 用于计算汇编指令长度,使用的是BlackBone的LDasm.c中的算法,我把他翻译成C#了
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class LDasm
|
||||||
|
{
|
||||||
|
const int F_INVALID = 0x01;
|
||||||
|
const int F_PREFIX = 0x02;
|
||||||
|
const int F_REX = 0x04;
|
||||||
|
const int F_MODRM = 0x08;
|
||||||
|
const int F_SIB = 0x10;
|
||||||
|
const int F_DISP = 0x20;
|
||||||
|
const int F_IMM = 0x40;
|
||||||
|
const int F_RELATIVE = 0x80;
|
||||||
|
|
||||||
|
const int OP_NONE = 0x00;
|
||||||
|
const int OP_INVALID = 0x80;
|
||||||
|
|
||||||
|
const int OP_DATA_I8 = 0x01;
|
||||||
|
const int OP_DATA_I16 = 0x02;
|
||||||
|
const int OP_DATA_I16_I32 = 0x04;
|
||||||
|
const int OP_DATA_I16_I32_I64 = 0x08;
|
||||||
|
const int OP_EXTENDED = 0x10;
|
||||||
|
const int OP_RELATIVE = 0x20;
|
||||||
|
const int OP_MODRM = 0x40;
|
||||||
|
const int OP_PREFIX = 0x80;
|
||||||
|
|
||||||
|
struct ldasm_data
|
||||||
|
{
|
||||||
|
public byte flags;
|
||||||
|
public byte rex;
|
||||||
|
public byte modrm;
|
||||||
|
public byte sib;
|
||||||
|
public byte opcd_offset;
|
||||||
|
public byte opcd_size;
|
||||||
|
public byte disp_offset;
|
||||||
|
public byte disp_size;
|
||||||
|
public byte imm_offset;
|
||||||
|
public byte imm_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte[] flags_table =
|
||||||
|
{
|
||||||
|
/* 00 */ OP_MODRM,
|
||||||
|
/* 01 */ OP_MODRM,
|
||||||
|
/* 02 */ OP_MODRM,
|
||||||
|
/* 03 */ OP_MODRM,
|
||||||
|
/* 04 */ OP_DATA_I8,
|
||||||
|
/* 05 */ OP_DATA_I16_I32,
|
||||||
|
/* 06 */ OP_NONE,
|
||||||
|
/* 07 */ OP_NONE,
|
||||||
|
/* 08 */ OP_MODRM,
|
||||||
|
/* 09 */ OP_MODRM,
|
||||||
|
/* 0A */ OP_MODRM,
|
||||||
|
/* 0B */ OP_MODRM,
|
||||||
|
/* 0C */ OP_DATA_I8,
|
||||||
|
/* 0D */ OP_DATA_I16_I32,
|
||||||
|
/* 0E */ OP_NONE,
|
||||||
|
/* 0F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 10 */ OP_MODRM,
|
||||||
|
/* 11 */ OP_MODRM,
|
||||||
|
/* 12 */ OP_MODRM,
|
||||||
|
/* 13 */ OP_MODRM,
|
||||||
|
/* 14 */ OP_DATA_I8,
|
||||||
|
/* 15 */ OP_DATA_I16_I32,
|
||||||
|
/* 16 */ OP_NONE,
|
||||||
|
/* 17 */ OP_NONE,
|
||||||
|
/* 18 */ OP_MODRM,
|
||||||
|
/* 19 */ OP_MODRM,
|
||||||
|
/* 1A */ OP_MODRM,
|
||||||
|
/* 1B */ OP_MODRM,
|
||||||
|
/* 1C */ OP_DATA_I8,
|
||||||
|
/* 1D */ OP_DATA_I16_I32,
|
||||||
|
/* 1E */ OP_NONE,
|
||||||
|
/* 1F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 20 */ OP_MODRM,
|
||||||
|
/* 21 */ OP_MODRM,
|
||||||
|
/* 22 */ OP_MODRM,
|
||||||
|
/* 23 */ OP_MODRM,
|
||||||
|
/* 24 */ OP_DATA_I8,
|
||||||
|
/* 25 */ OP_DATA_I16_I32,
|
||||||
|
/* 26 */ OP_PREFIX,
|
||||||
|
/* 27 */ OP_NONE,
|
||||||
|
/* 28 */ OP_MODRM,
|
||||||
|
/* 29 */ OP_MODRM,
|
||||||
|
/* 2A */ OP_MODRM,
|
||||||
|
/* 2B */ OP_MODRM,
|
||||||
|
/* 2C */ OP_DATA_I8,
|
||||||
|
/* 2D */ OP_DATA_I16_I32,
|
||||||
|
/* 2E */ OP_PREFIX,
|
||||||
|
/* 2F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 30 */ OP_MODRM,
|
||||||
|
/* 31 */ OP_MODRM,
|
||||||
|
/* 32 */ OP_MODRM,
|
||||||
|
/* 33 */ OP_MODRM,
|
||||||
|
/* 34 */ OP_DATA_I8,
|
||||||
|
/* 35 */ OP_DATA_I16_I32,
|
||||||
|
/* 36 */ OP_PREFIX,
|
||||||
|
/* 37 */ OP_NONE,
|
||||||
|
/* 38 */ OP_MODRM,
|
||||||
|
/* 39 */ OP_MODRM,
|
||||||
|
/* 3A */ OP_MODRM,
|
||||||
|
/* 3B */ OP_MODRM,
|
||||||
|
/* 3C */ OP_DATA_I8,
|
||||||
|
/* 3D */ OP_DATA_I16_I32,
|
||||||
|
/* 3E */ OP_PREFIX,
|
||||||
|
/* 3F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 40 */ OP_NONE,
|
||||||
|
/* 41 */ OP_NONE,
|
||||||
|
/* 42 */ OP_NONE,
|
||||||
|
/* 43 */ OP_NONE,
|
||||||
|
/* 44 */ OP_NONE,
|
||||||
|
/* 45 */ OP_NONE,
|
||||||
|
/* 46 */ OP_NONE,
|
||||||
|
/* 47 */ OP_NONE,
|
||||||
|
/* 48 */ OP_NONE,
|
||||||
|
/* 49 */ OP_NONE,
|
||||||
|
/* 4A */ OP_NONE,
|
||||||
|
/* 4B */ OP_NONE,
|
||||||
|
/* 4C */ OP_NONE,
|
||||||
|
/* 4D */ OP_NONE,
|
||||||
|
/* 4E */ OP_NONE,
|
||||||
|
/* 4F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 50 */ OP_NONE,
|
||||||
|
/* 51 */ OP_NONE,
|
||||||
|
/* 52 */ OP_NONE,
|
||||||
|
/* 53 */ OP_NONE,
|
||||||
|
/* 54 */ OP_NONE,
|
||||||
|
/* 55 */ OP_NONE,
|
||||||
|
/* 56 */ OP_NONE,
|
||||||
|
/* 57 */ OP_NONE,
|
||||||
|
/* 58 */ OP_NONE,
|
||||||
|
/* 59 */ OP_NONE,
|
||||||
|
/* 5A */ OP_NONE,
|
||||||
|
/* 5B */ OP_NONE,
|
||||||
|
/* 5C */ OP_NONE,
|
||||||
|
/* 5D */ OP_NONE,
|
||||||
|
/* 5E */ OP_NONE,
|
||||||
|
/* 5F */ OP_NONE,
|
||||||
|
/* 60 */ OP_NONE,
|
||||||
|
|
||||||
|
/* 61 */ OP_NONE,
|
||||||
|
/* 62 */ OP_MODRM,
|
||||||
|
/* 63 */ OP_MODRM,
|
||||||
|
/* 64 */ OP_PREFIX,
|
||||||
|
/* 65 */ OP_PREFIX,
|
||||||
|
/* 66 */ OP_PREFIX,
|
||||||
|
/* 67 */ OP_PREFIX,
|
||||||
|
/* 68 */ OP_DATA_I16_I32,
|
||||||
|
/* 69 */ OP_MODRM | OP_DATA_I16_I32,
|
||||||
|
/* 6A */ OP_DATA_I8,
|
||||||
|
/* 6B */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 6C */ OP_NONE,
|
||||||
|
/* 6D */ OP_NONE,
|
||||||
|
/* 6E */ OP_NONE,
|
||||||
|
/* 6F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 70 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 71 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 72 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 73 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 74 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 75 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 76 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 77 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 78 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 79 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7A */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7B */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7C */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7D */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7E */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* 7F */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
|
||||||
|
/* 80 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 81 */ OP_MODRM | OP_DATA_I16_I32,
|
||||||
|
/* 82 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 83 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 84 */ OP_MODRM,
|
||||||
|
/* 85 */ OP_MODRM,
|
||||||
|
/* 86 */ OP_MODRM,
|
||||||
|
/* 87 */ OP_MODRM,
|
||||||
|
/* 88 */ OP_MODRM,
|
||||||
|
/* 89 */ OP_MODRM,
|
||||||
|
/* 8A */ OP_MODRM,
|
||||||
|
/* 8B */ OP_MODRM,
|
||||||
|
/* 8C */ OP_MODRM,
|
||||||
|
/* 8D */ OP_MODRM,
|
||||||
|
/* 8E */ OP_MODRM,
|
||||||
|
/* 8F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 90 */ OP_NONE,
|
||||||
|
/* 91 */ OP_NONE,
|
||||||
|
/* 92 */ OP_NONE,
|
||||||
|
/* 93 */ OP_NONE,
|
||||||
|
/* 94 */ OP_NONE,
|
||||||
|
/* 95 */ OP_NONE,
|
||||||
|
/* 96 */ OP_NONE,
|
||||||
|
/* 97 */ OP_NONE,
|
||||||
|
/* 98 */ OP_NONE,
|
||||||
|
/* 99 */ OP_NONE,
|
||||||
|
/* 9A */ OP_DATA_I16 | OP_DATA_I16_I32,
|
||||||
|
/* 9B */ OP_NONE,
|
||||||
|
/* 9C */ OP_NONE,
|
||||||
|
/* 9D */ OP_NONE,
|
||||||
|
/* 9E */ OP_NONE,
|
||||||
|
/* 9F */ OP_NONE,
|
||||||
|
|
||||||
|
/* A0 */ OP_DATA_I8,
|
||||||
|
/* A1 */ OP_DATA_I16_I32_I64,
|
||||||
|
/* A2 */ OP_DATA_I8,
|
||||||
|
/* A3 */ OP_DATA_I16_I32_I64,
|
||||||
|
/* A4 */ OP_NONE,
|
||||||
|
/* A5 */ OP_NONE,
|
||||||
|
/* A6 */ OP_NONE,
|
||||||
|
/* A7 */ OP_NONE,
|
||||||
|
/* A8 */ OP_DATA_I8,
|
||||||
|
/* A9 */ OP_DATA_I16_I32,
|
||||||
|
/* AA */ OP_NONE,
|
||||||
|
/* AB */ OP_NONE,
|
||||||
|
/* AC */ OP_NONE,
|
||||||
|
/* AD */ OP_NONE,
|
||||||
|
/* AE */ OP_NONE,
|
||||||
|
/* AF */ OP_NONE,
|
||||||
|
|
||||||
|
/* B0 */ OP_DATA_I8,
|
||||||
|
/* B1 */ OP_DATA_I8,
|
||||||
|
/* B2 */ OP_DATA_I8,
|
||||||
|
/* B3 */ OP_DATA_I8,
|
||||||
|
/* B4 */ OP_DATA_I8,
|
||||||
|
/* B5 */ OP_DATA_I8,
|
||||||
|
/* B6 */ OP_DATA_I8,
|
||||||
|
/* B7 */ OP_DATA_I8,
|
||||||
|
/* B8 */ OP_DATA_I16_I32_I64,
|
||||||
|
/* B9 */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BA */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BB */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BC */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BD */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BE */ OP_DATA_I16_I32_I64,
|
||||||
|
/* BF */ OP_DATA_I16_I32_I64,
|
||||||
|
|
||||||
|
/* C0 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* C1 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* C2 */ OP_DATA_I16,
|
||||||
|
/* C3 */ OP_NONE,
|
||||||
|
/* C4 */ OP_MODRM,
|
||||||
|
/* C5 */ OP_MODRM,
|
||||||
|
/* C6 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* C7 */ OP_MODRM | OP_DATA_I16_I32,
|
||||||
|
/* C8 */ OP_DATA_I8 | OP_DATA_I16,
|
||||||
|
/* C9 */ OP_NONE,
|
||||||
|
/* CA */ OP_DATA_I16,
|
||||||
|
/* CB */ OP_NONE,
|
||||||
|
/* CC */ OP_NONE,
|
||||||
|
/* CD */ OP_DATA_I8,
|
||||||
|
/* CE */ OP_NONE,
|
||||||
|
/* CF */ OP_NONE,
|
||||||
|
|
||||||
|
/* D0 */ OP_MODRM,
|
||||||
|
/* D1 */ OP_MODRM,
|
||||||
|
/* D2 */ OP_MODRM,
|
||||||
|
/* D3 */ OP_MODRM,
|
||||||
|
/* D4 */ OP_DATA_I8,
|
||||||
|
/* D5 */ OP_DATA_I8,
|
||||||
|
/* D6 */ OP_NONE,
|
||||||
|
/* D7 */ OP_NONE,
|
||||||
|
/* D8 */ OP_MODRM,
|
||||||
|
/* D9 */ OP_MODRM,
|
||||||
|
/* DA */ OP_MODRM,
|
||||||
|
/* DB */ OP_MODRM,
|
||||||
|
/* DC */ OP_MODRM,
|
||||||
|
/* DD */ OP_MODRM,
|
||||||
|
/* DE */ OP_MODRM,
|
||||||
|
/* DF */ OP_MODRM,
|
||||||
|
|
||||||
|
/* E0 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* E1 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* E2 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* E3 */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* E4 */ OP_DATA_I8,
|
||||||
|
/* E5 */ OP_DATA_I8,
|
||||||
|
/* E6 */ OP_DATA_I8,
|
||||||
|
/* E7 */ OP_DATA_I8,
|
||||||
|
/* E8 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* E9 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* EA */ OP_DATA_I16 | OP_DATA_I16_I32,
|
||||||
|
/* EB */ OP_RELATIVE | OP_DATA_I8,
|
||||||
|
/* EC */ OP_NONE,
|
||||||
|
/* ED */ OP_NONE,
|
||||||
|
/* EE */ OP_NONE,
|
||||||
|
/* EF */ OP_NONE,
|
||||||
|
|
||||||
|
/* F0 */ OP_PREFIX,
|
||||||
|
/* F1 */ OP_NONE,
|
||||||
|
/* F2 */ OP_PREFIX,
|
||||||
|
/* F3 */ OP_PREFIX,
|
||||||
|
/* F4 */ OP_NONE,
|
||||||
|
/* F5 */ OP_NONE,
|
||||||
|
/* F6 */ OP_MODRM,
|
||||||
|
/* F7 */ OP_MODRM,
|
||||||
|
/* F8 */ OP_NONE,
|
||||||
|
/* F9 */ OP_NONE,
|
||||||
|
/* FA */ OP_NONE,
|
||||||
|
/* FB */ OP_NONE,
|
||||||
|
/* FC */ OP_NONE,
|
||||||
|
/* FD */ OP_NONE,
|
||||||
|
/* FE */ OP_MODRM,
|
||||||
|
/* FF */ OP_MODRM
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte[] flags_table_ex =
|
||||||
|
{
|
||||||
|
/* 0F00 */ OP_MODRM,
|
||||||
|
/* 0F01 */ OP_MODRM,
|
||||||
|
/* 0F02 */ OP_MODRM,
|
||||||
|
/* 0F03 */ OP_MODRM,
|
||||||
|
/* 0F04 */ OP_INVALID,
|
||||||
|
/* 0F05 */ OP_NONE,
|
||||||
|
/* 0F06 */ OP_NONE,
|
||||||
|
/* 0F07 */ OP_NONE,
|
||||||
|
/* 0F08 */ OP_NONE,
|
||||||
|
/* 0F09 */ OP_NONE,
|
||||||
|
/* 0F0A */ OP_INVALID,
|
||||||
|
/* 0F0B */ OP_NONE,
|
||||||
|
/* 0F0C */ OP_INVALID,
|
||||||
|
/* 0F0D */ OP_MODRM,
|
||||||
|
/* 0F0E */ OP_INVALID,
|
||||||
|
/* 0F0F */ OP_MODRM | OP_DATA_I8, //3Dnow
|
||||||
|
|
||||||
|
/* 0F10 */ OP_MODRM,
|
||||||
|
/* 0F11 */ OP_MODRM,
|
||||||
|
/* 0F12 */ OP_MODRM,
|
||||||
|
/* 0F13 */ OP_MODRM,
|
||||||
|
/* 0F14 */ OP_MODRM,
|
||||||
|
/* 0F15 */ OP_MODRM,
|
||||||
|
/* 0F16 */ OP_MODRM,
|
||||||
|
/* 0F17 */ OP_MODRM,
|
||||||
|
/* 0F18 */ OP_MODRM,
|
||||||
|
/* 0F19 */ OP_INVALID,
|
||||||
|
/* 0F1A */ OP_INVALID,
|
||||||
|
/* 0F1B */ OP_INVALID,
|
||||||
|
/* 0F1C */ OP_INVALID,
|
||||||
|
/* 0F1D */ OP_INVALID,
|
||||||
|
/* 0F1E */ OP_INVALID,
|
||||||
|
/* 0F1F */ OP_NONE,
|
||||||
|
|
||||||
|
/* 0F20 */ OP_MODRM,
|
||||||
|
/* 0F21 */ OP_MODRM,
|
||||||
|
/* 0F22 */ OP_MODRM,
|
||||||
|
/* 0F23 */ OP_MODRM,
|
||||||
|
/* 0F24 */ OP_MODRM | OP_EXTENDED, //SSE5
|
||||||
|
/* 0F25 */ OP_INVALID,
|
||||||
|
/* 0F26 */ OP_MODRM,
|
||||||
|
/* 0F27 */ OP_INVALID,
|
||||||
|
/* 0F28 */ OP_MODRM,
|
||||||
|
/* 0F29 */ OP_MODRM,
|
||||||
|
/* 0F2A */ OP_MODRM,
|
||||||
|
/* 0F2B */ OP_MODRM,
|
||||||
|
/* 0F2C */ OP_MODRM,
|
||||||
|
/* 0F2D */ OP_MODRM,
|
||||||
|
/* 0F2E */ OP_MODRM,
|
||||||
|
/* 0F2F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0F30 */ OP_NONE,
|
||||||
|
/* 0F31 */ OP_NONE,
|
||||||
|
/* 0F32 */ OP_NONE,
|
||||||
|
/* 0F33 */ OP_NONE,
|
||||||
|
/* 0F34 */ OP_NONE,
|
||||||
|
/* 0F35 */ OP_NONE,
|
||||||
|
/* 0F36 */ OP_INVALID,
|
||||||
|
/* 0F37 */ OP_NONE,
|
||||||
|
/* 0F38 */ OP_MODRM | OP_EXTENDED,
|
||||||
|
/* 0F39 */ OP_INVALID,
|
||||||
|
/* 0F3A */ OP_MODRM | OP_EXTENDED | OP_DATA_I8,
|
||||||
|
/* 0F3B */ OP_INVALID,
|
||||||
|
/* 0F3C */ OP_INVALID,
|
||||||
|
/* 0F3D */ OP_INVALID,
|
||||||
|
/* 0F3E */ OP_INVALID,
|
||||||
|
/* 0F3F */ OP_INVALID,
|
||||||
|
|
||||||
|
/* 0F40 */ OP_MODRM,
|
||||||
|
/* 0F41 */ OP_MODRM,
|
||||||
|
/* 0F42 */ OP_MODRM,
|
||||||
|
/* 0F43 */ OP_MODRM,
|
||||||
|
/* 0F44 */ OP_MODRM,
|
||||||
|
/* 0F45 */ OP_MODRM,
|
||||||
|
/* 0F46 */ OP_MODRM,
|
||||||
|
/* 0F47 */ OP_MODRM,
|
||||||
|
/* 0F48 */ OP_MODRM,
|
||||||
|
/* 0F49 */ OP_MODRM,
|
||||||
|
/* 0F4A */ OP_MODRM,
|
||||||
|
/* 0F4B */ OP_MODRM,
|
||||||
|
/* 0F4C */ OP_MODRM,
|
||||||
|
/* 0F4D */ OP_MODRM,
|
||||||
|
/* 0F4E */ OP_MODRM,
|
||||||
|
/* 0F4F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0F50 */ OP_MODRM,
|
||||||
|
/* 0F51 */ OP_MODRM,
|
||||||
|
/* 0F52 */ OP_MODRM,
|
||||||
|
/* 0F53 */ OP_MODRM,
|
||||||
|
/* 0F54 */ OP_MODRM,
|
||||||
|
/* 0F55 */ OP_MODRM,
|
||||||
|
/* 0F56 */ OP_MODRM,
|
||||||
|
/* 0F57 */ OP_MODRM,
|
||||||
|
/* 0F58 */ OP_MODRM,
|
||||||
|
/* 0F59 */ OP_MODRM,
|
||||||
|
/* 0F5A */ OP_MODRM,
|
||||||
|
/* 0F5B */ OP_MODRM,
|
||||||
|
/* 0F5C */ OP_MODRM,
|
||||||
|
/* 0F5D */ OP_MODRM,
|
||||||
|
/* 0F5E */ OP_MODRM,
|
||||||
|
/* 0F5F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0F60 */ OP_MODRM,
|
||||||
|
/* 0F61 */ OP_MODRM,
|
||||||
|
/* 0F62 */ OP_MODRM,
|
||||||
|
/* 0F63 */ OP_MODRM,
|
||||||
|
/* 0F64 */ OP_MODRM,
|
||||||
|
/* 0F65 */ OP_MODRM,
|
||||||
|
/* 0F66 */ OP_MODRM,
|
||||||
|
/* 0F67 */ OP_MODRM,
|
||||||
|
/* 0F68 */ OP_MODRM,
|
||||||
|
/* 0F69 */ OP_MODRM,
|
||||||
|
/* 0F6A */ OP_MODRM,
|
||||||
|
/* 0F6B */ OP_MODRM,
|
||||||
|
/* 0F6C */ OP_MODRM,
|
||||||
|
/* 0F6D */ OP_MODRM,
|
||||||
|
/* 0F6E */ OP_MODRM,
|
||||||
|
/* 0F6F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0F70 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0F71 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0F72 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0F73 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0F74 */ OP_MODRM,
|
||||||
|
/* 0F75 */ OP_MODRM,
|
||||||
|
/* 0F76 */ OP_MODRM,
|
||||||
|
/* 0F77 */ OP_NONE,
|
||||||
|
/* 0F78 */ OP_MODRM,
|
||||||
|
/* 0F79 */ OP_MODRM,
|
||||||
|
/* 0F7A */ OP_INVALID,
|
||||||
|
/* 0F7B */ OP_INVALID,
|
||||||
|
/* 0F7C */ OP_MODRM,
|
||||||
|
/* 0F7D */ OP_MODRM,
|
||||||
|
/* 0F7E */ OP_MODRM,
|
||||||
|
/* 0F7F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0F80 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F81 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F82 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F83 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F84 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F85 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F86 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F87 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F88 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F89 */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8A */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8B */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8C */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8D */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8E */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
/* 0F8F */ OP_RELATIVE | OP_DATA_I16_I32,
|
||||||
|
|
||||||
|
/* 0F90 */ OP_MODRM,
|
||||||
|
/* 0F91 */ OP_MODRM,
|
||||||
|
/* 0F92 */ OP_MODRM,
|
||||||
|
/* 0F93 */ OP_MODRM,
|
||||||
|
/* 0F94 */ OP_MODRM,
|
||||||
|
/* 0F95 */ OP_MODRM,
|
||||||
|
/* 0F96 */ OP_MODRM,
|
||||||
|
/* 0F97 */ OP_MODRM,
|
||||||
|
/* 0F98 */ OP_MODRM,
|
||||||
|
/* 0F99 */ OP_MODRM,
|
||||||
|
/* 0F9A */ OP_MODRM,
|
||||||
|
/* 0F9B */ OP_MODRM,
|
||||||
|
/* 0F9C */ OP_MODRM,
|
||||||
|
/* 0F9D */ OP_MODRM,
|
||||||
|
/* 0F9E */ OP_MODRM,
|
||||||
|
/* 0F9F */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0FA0 */ OP_NONE,
|
||||||
|
/* 0FA1 */ OP_NONE,
|
||||||
|
/* 0FA2 */ OP_NONE,
|
||||||
|
/* 0FA3 */ OP_MODRM,
|
||||||
|
/* 0FA4 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FA5 */ OP_MODRM,
|
||||||
|
/* 0FA6 */ OP_INVALID,
|
||||||
|
/* 0FA7 */ OP_INVALID,
|
||||||
|
/* 0FA8 */ OP_NONE,
|
||||||
|
/* 0FA9 */ OP_NONE,
|
||||||
|
/* 0FAA */ OP_NONE,
|
||||||
|
/* 0FAB */ OP_MODRM,
|
||||||
|
/* 0FAC */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FAD */ OP_MODRM,
|
||||||
|
/* 0FAE */ OP_MODRM,
|
||||||
|
/* 0FAF */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0FB0 */ OP_MODRM,
|
||||||
|
/* 0FB1 */ OP_MODRM,
|
||||||
|
/* 0FB2 */ OP_MODRM,
|
||||||
|
/* 0FB3 */ OP_MODRM,
|
||||||
|
/* 0FB4 */ OP_MODRM,
|
||||||
|
/* 0FB5 */ OP_MODRM,
|
||||||
|
/* 0FB6 */ OP_MODRM,
|
||||||
|
/* 0FB7 */ OP_MODRM,
|
||||||
|
/* 0FB8 */ OP_MODRM,
|
||||||
|
/* 0FB9 */ OP_MODRM,
|
||||||
|
/* 0FBA */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FBB */ OP_MODRM,
|
||||||
|
/* 0FBC */ OP_MODRM,
|
||||||
|
/* 0FBD */ OP_MODRM,
|
||||||
|
/* 0FBE */ OP_MODRM,
|
||||||
|
/* 0FBF */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0FC0 */ OP_MODRM,
|
||||||
|
/* 0FC1 */ OP_MODRM,
|
||||||
|
/* 0FC2 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FC3 */ OP_MODRM,
|
||||||
|
/* 0FC4 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FC5 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FC6 */ OP_MODRM | OP_DATA_I8,
|
||||||
|
/* 0FC7 */ OP_MODRM,
|
||||||
|
/* 0FC8 */ OP_NONE,
|
||||||
|
/* 0FC9 */ OP_NONE,
|
||||||
|
/* 0FCA */ OP_NONE,
|
||||||
|
/* 0FCB */ OP_NONE,
|
||||||
|
/* 0FCC */ OP_NONE,
|
||||||
|
/* 0FCD */ OP_NONE,
|
||||||
|
/* 0FCE */ OP_NONE,
|
||||||
|
/* 0FCF */ OP_NONE,
|
||||||
|
|
||||||
|
/* 0FD0 */ OP_MODRM,
|
||||||
|
/* 0FD1 */ OP_MODRM,
|
||||||
|
/* 0FD2 */ OP_MODRM,
|
||||||
|
/* 0FD3 */ OP_MODRM,
|
||||||
|
/* 0FD4 */ OP_MODRM,
|
||||||
|
/* 0FD5 */ OP_MODRM,
|
||||||
|
/* 0FD6 */ OP_MODRM,
|
||||||
|
/* 0FD7 */ OP_MODRM,
|
||||||
|
/* 0FD8 */ OP_MODRM,
|
||||||
|
/* 0FD9 */ OP_MODRM,
|
||||||
|
/* 0FDA */ OP_MODRM,
|
||||||
|
/* 0FDB */ OP_MODRM,
|
||||||
|
/* 0FDC */ OP_MODRM,
|
||||||
|
/* 0FDD */ OP_MODRM,
|
||||||
|
/* 0FDE */ OP_MODRM,
|
||||||
|
/* 0FDF */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0FE0 */ OP_MODRM,
|
||||||
|
/* 0FE1 */ OP_MODRM,
|
||||||
|
/* 0FE2 */ OP_MODRM,
|
||||||
|
/* 0FE3 */ OP_MODRM,
|
||||||
|
/* 0FE4 */ OP_MODRM,
|
||||||
|
/* 0FE5 */ OP_MODRM,
|
||||||
|
/* 0FE6 */ OP_MODRM,
|
||||||
|
/* 0FE7 */ OP_MODRM,
|
||||||
|
/* 0FE8 */ OP_MODRM,
|
||||||
|
/* 0FE9 */ OP_MODRM,
|
||||||
|
/* 0FEA */ OP_MODRM,
|
||||||
|
/* 0FEB */ OP_MODRM,
|
||||||
|
/* 0FEC */ OP_MODRM,
|
||||||
|
/* 0FED */ OP_MODRM,
|
||||||
|
/* 0FEE */ OP_MODRM,
|
||||||
|
/* 0FEF */ OP_MODRM,
|
||||||
|
|
||||||
|
/* 0FF0 */ OP_MODRM,
|
||||||
|
/* 0FF1 */ OP_MODRM,
|
||||||
|
/* 0FF2 */ OP_MODRM,
|
||||||
|
/* 0FF3 */ OP_MODRM,
|
||||||
|
/* 0FF4 */ OP_MODRM,
|
||||||
|
/* 0FF5 */ OP_MODRM,
|
||||||
|
/* 0FF6 */ OP_MODRM,
|
||||||
|
/* 0FF7 */ OP_MODRM,
|
||||||
|
/* 0FF8 */ OP_MODRM,
|
||||||
|
/* 0FF9 */ OP_MODRM,
|
||||||
|
/* 0FFA */ OP_MODRM,
|
||||||
|
/* 0FFB */ OP_MODRM,
|
||||||
|
/* 0FFC */ OP_MODRM,
|
||||||
|
/* 0FFD */ OP_MODRM,
|
||||||
|
/* 0FFE */ OP_MODRM,
|
||||||
|
/* 0FFF */ OP_INVALID,
|
||||||
|
};
|
||||||
|
|
||||||
|
static byte cflags(byte op)
|
||||||
|
{
|
||||||
|
return flags_table[op];
|
||||||
|
}
|
||||||
|
|
||||||
|
static byte cflags_ex(byte op)
|
||||||
|
{
|
||||||
|
return flags_table_ex[op];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算大于等于 size 字节的最少指令的长度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static uint SizeofMinNumByte(void* code, int size)
|
||||||
|
{
|
||||||
|
if (IsARM())
|
||||||
|
return (uint)((size + 3) / 4) * 4; // 此为 jit 模式下的长度,不再支持 thumb
|
||||||
|
|
||||||
|
uint Length;
|
||||||
|
byte* pOpcode;
|
||||||
|
uint Result = 0;
|
||||||
|
ldasm_data data = new ldasm_data();
|
||||||
|
bool is64 = IntPtr.Size == 8;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Length = ldasm(code, data, is64);
|
||||||
|
|
||||||
|
pOpcode = (byte*)code + data.opcd_offset;
|
||||||
|
Result += Length;
|
||||||
|
if (Result >= size)
|
||||||
|
break;
|
||||||
|
if ((Length == 1) && (*pOpcode == 0xCC))
|
||||||
|
break;
|
||||||
|
|
||||||
|
code = (void*)((ulong)code + Length);
|
||||||
|
|
||||||
|
} while (Length>0);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool? s_isArm;
|
||||||
|
public static bool IsARM()
|
||||||
|
{
|
||||||
|
if(s_isArm.HasValue)
|
||||||
|
return s_isArm.Value;
|
||||||
|
|
||||||
|
var arch = RuntimeInformation.ProcessArchitecture;
|
||||||
|
s_isArm = arch == Architecture.Arm || arch == Architecture.Arm64;
|
||||||
|
|
||||||
|
return s_isArm.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsArm32()
|
||||||
|
{
|
||||||
|
return IsARM() && IntPtr.Size == 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsArm64()
|
||||||
|
{
|
||||||
|
return IsARM() && IntPtr.Size == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool? s_isiOS;
|
||||||
|
public static bool IsiOS()
|
||||||
|
{
|
||||||
|
if(s_isiOS.HasValue)
|
||||||
|
return s_isiOS.Value;
|
||||||
|
|
||||||
|
s_isiOS = UnityEngine.SystemInfo.operatingSystem.ToLower().Contains("ios");
|
||||||
|
return s_isiOS.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool? s_isIL2CPP;
|
||||||
|
public static bool IsIL2CPP()
|
||||||
|
{
|
||||||
|
if (s_isIL2CPP.HasValue)
|
||||||
|
return s_isIL2CPP.Value;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] ilBody = typeof(LDasm).GetMethod("IsIL2CPP").GetMethodBody().GetILAsByteArray();
|
||||||
|
if (ilBody == null || ilBody.Length == 0)
|
||||||
|
s_isIL2CPP = true;
|
||||||
|
else
|
||||||
|
s_isIL2CPP = false;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
s_isIL2CPP = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_isIL2CPP.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsThumb(IntPtr code)
|
||||||
|
{
|
||||||
|
return IsArm32() && ((long)code & 0x1) == 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算 thumb 指令长度
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <param name="size"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static uint CalcARMThumbMinLen(void* code, int size)
|
||||||
|
{
|
||||||
|
uint len = 0;
|
||||||
|
|
||||||
|
ushort* ins = (ushort*)code;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (len >= size)
|
||||||
|
return len;
|
||||||
|
|
||||||
|
if (((*ins >> 13) & 3) == 3)
|
||||||
|
{
|
||||||
|
ins += 2;
|
||||||
|
len += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ins++;
|
||||||
|
len += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint ldasm(void* code, ldasm_data ld, bool is64)
|
||||||
|
{
|
||||||
|
byte* p = (byte*)code;
|
||||||
|
byte s, op, f;
|
||||||
|
byte rexw, pr_66, pr_67;
|
||||||
|
|
||||||
|
s = rexw = pr_66 = pr_67 = 0;
|
||||||
|
|
||||||
|
/* dummy check */
|
||||||
|
if ((int)code==0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* init output data */
|
||||||
|
//memset(ld, 0, sizeof(ldasm_data));
|
||||||
|
|
||||||
|
/* phase 1: parse prefixies */
|
||||||
|
while ((cflags(*p) & OP_PREFIX)!=0)
|
||||||
|
{
|
||||||
|
if (*p == 0x66)
|
||||||
|
pr_66 = 1;
|
||||||
|
if (*p == 0x67)
|
||||||
|
pr_67 = 1;
|
||||||
|
p++; s++;
|
||||||
|
ld.flags |= F_PREFIX;
|
||||||
|
if (s == 15)
|
||||||
|
{
|
||||||
|
ld.flags |= F_INVALID;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse REX prefix */
|
||||||
|
if (is64 && *p >> 4 == 4)
|
||||||
|
{
|
||||||
|
ld.rex = *p;
|
||||||
|
rexw = (byte)((ld.rex >> 3) & 1);
|
||||||
|
ld.flags |= F_REX;
|
||||||
|
p++; s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* can be only one REX prefix */
|
||||||
|
if (is64 && *p >> 4 == 4)
|
||||||
|
{
|
||||||
|
ld.flags |= F_INVALID;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* phase 2: parse opcode */
|
||||||
|
ld.opcd_offset = (byte)(p - (byte*)code);
|
||||||
|
ld.opcd_size = 1;
|
||||||
|
op = *p++; s++;
|
||||||
|
|
||||||
|
/* is 2 byte opcode? */
|
||||||
|
if (op == 0x0F)
|
||||||
|
{
|
||||||
|
op = *p++; s++;
|
||||||
|
ld.opcd_size++;
|
||||||
|
f = cflags_ex(op);
|
||||||
|
if ((f & OP_INVALID)!=0)
|
||||||
|
{
|
||||||
|
ld.flags |= F_INVALID;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
/* for SSE instructions */
|
||||||
|
if ((f & OP_EXTENDED)!=0)
|
||||||
|
{
|
||||||
|
op = *p++; s++;
|
||||||
|
ld.opcd_size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = cflags(op);
|
||||||
|
/* pr_66 = pr_67 for opcodes A0-A3 */
|
||||||
|
if (op >= 0xA0 && op <= 0xA3)
|
||||||
|
pr_66 = pr_67;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* phase 3: parse ModR/M, SIB and DISP */
|
||||||
|
if ((f & OP_MODRM)!=0)
|
||||||
|
{
|
||||||
|
byte mod = (byte)(*p >> 6);
|
||||||
|
byte ro = (byte)((*p & 0x38) >> 3);
|
||||||
|
byte rm = (byte)(*p & 7);
|
||||||
|
|
||||||
|
ld.modrm = *p++; s++;
|
||||||
|
ld.flags |= F_MODRM;
|
||||||
|
|
||||||
|
/* in F6,F7 opcodes immediate data present if R/O == 0 */
|
||||||
|
if (op == 0xF6 && (ro == 0 || ro == 1))
|
||||||
|
f |= OP_DATA_I8;
|
||||||
|
if (op == 0xF7 && (ro == 0 || ro == 1))
|
||||||
|
f |= OP_DATA_I16_I32_I64;
|
||||||
|
|
||||||
|
/* is SIB byte exist? */
|
||||||
|
if (mod != 3 && rm == 4 && !(!is64 && pr_67!=0))
|
||||||
|
{
|
||||||
|
ld.sib = *p++; s++;
|
||||||
|
ld.flags |= F_SIB;
|
||||||
|
|
||||||
|
/* if base == 5 and mod == 0 */
|
||||||
|
if ((ld.sib & 7) == 5 && mod == 0)
|
||||||
|
{
|
||||||
|
ld.disp_size = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mod)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
if (is64)
|
||||||
|
{
|
||||||
|
if (rm == 5)
|
||||||
|
{
|
||||||
|
ld.disp_size = 4;
|
||||||
|
if (is64)
|
||||||
|
ld.flags |= F_RELATIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pr_67!=0)
|
||||||
|
{
|
||||||
|
if (rm == 6)
|
||||||
|
ld.disp_size = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (rm == 5)
|
||||||
|
ld.disp_size = 4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ld.disp_size = 1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (is64)
|
||||||
|
ld.disp_size = 4;
|
||||||
|
else if (pr_67!=0)
|
||||||
|
ld.disp_size = 2;
|
||||||
|
else
|
||||||
|
ld.disp_size = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ld.disp_size>0)
|
||||||
|
{
|
||||||
|
ld.disp_offset = (byte)(p - (byte*)code);
|
||||||
|
p += ld.disp_size;
|
||||||
|
s += ld.disp_size;
|
||||||
|
ld.flags |= F_DISP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* phase 4: parse immediate data */
|
||||||
|
if (rexw!=0 && (f & OP_DATA_I16_I32_I64)!=0)
|
||||||
|
ld.imm_size = 8;
|
||||||
|
else if ((f & OP_DATA_I16_I32)!=0 || (f & OP_DATA_I16_I32_I64)!=0)
|
||||||
|
ld.imm_size = (byte)(4 - (pr_66 << 1));
|
||||||
|
|
||||||
|
/* if exist, add OP_DATA_I16 and OP_DATA_I8 size */
|
||||||
|
ld.imm_size += (byte)(f & 3);
|
||||||
|
|
||||||
|
if ((ld.imm_size)!=0)
|
||||||
|
{
|
||||||
|
s += ld.imm_size;
|
||||||
|
ld.imm_offset = (byte)(p - (byte*)code);
|
||||||
|
ld.flags |= F_IMM;
|
||||||
|
if ((f & OP_RELATIVE)!=0)
|
||||||
|
ld.flags |= F_RELATIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* instruction is too long */
|
||||||
|
if (s > 15)
|
||||||
|
ld.flags |= F_INVALID;
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3c561c9729c367e4fbef63f4ec56f268
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,381 @@
|
||||||
|
/*
|
||||||
|
Desc: 一个可以运行时 Hook Mono 方法的工具,让你可以无需修改 UnityEditor.dll 等文件就可以重写其函数功能
|
||||||
|
Author: Misaka Mikoto
|
||||||
|
Github: https://github.com/Misaka-Mikoto-Tech/MonoHook
|
||||||
|
*/
|
||||||
|
|
||||||
|
using DotNetDetour;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Unity.Collections.LowLevel.Unsafe;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using UnityEditor;
|
||||||
|
#endif
|
||||||
|
using UnityEngine;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
>>>>>>> 原始 UnityEditor.LogEntries.Clear 一型(.net 4.x)
|
||||||
|
0000000000403A00 < | 55 | push rbp |
|
||||||
|
0000000000403A01 | 48 8B EC | mov rbp,rsp |
|
||||||
|
0000000000403A04 | 48 81 EC 80 00 00 00 | sub rsp,80 |
|
||||||
|
0000000000403A0B | 48 89 65 B0 | mov qword ptr ss:[rbp-50],rsp |
|
||||||
|
0000000000403A0F | 48 89 6D A8 | mov qword ptr ss:[rbp-58],rbp |
|
||||||
|
0000000000403A13 | 48 89 5D C8 | mov qword ptr ss:[rbp-38],rbx | <<
|
||||||
|
0000000000403A17 | 48 89 75 D0 | mov qword ptr ss:[rbp-30],rsi |
|
||||||
|
0000000000403A1B | 48 89 7D D8 | mov qword ptr ss:[rbp-28],rdi |
|
||||||
|
0000000000403A1F | 4C 89 65 E0 | mov qword ptr ss:[rbp-20],r12 |
|
||||||
|
0000000000403A23 | 4C 89 6D E8 | mov qword ptr ss:[rbp-18],r13 |
|
||||||
|
0000000000403A27 | 4C 89 75 F0 | mov qword ptr ss:[rbp-10],r14 |
|
||||||
|
0000000000403A2B | 4C 89 7D F8 | mov qword ptr ss:[rbp-8],r15 |
|
||||||
|
0000000000403A2F | 49 BB 00 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D00 |
|
||||||
|
0000000000403A39 | 4C 89 5D B8 | mov qword ptr ss:[rbp-48],r11 |
|
||||||
|
0000000000403A3D | 49 BB 08 2D 1E 1A FE 7F 00 00 | mov r11,7FFE1A1E2D08 |
|
||||||
|
|
||||||
|
|
||||||
|
>>>>>>> 二型(.net 2.x)
|
||||||
|
0000000000403E8F | 55 | push rbp |
|
||||||
|
0000000000403E90 | 48 8B EC | mov rbp,rsp |
|
||||||
|
0000000000403E93 | 48 83 EC 70 | sub rsp,70 |
|
||||||
|
0000000000403E97 | 48 89 65 C8 | mov qword ptr ss:[rbp-38],rsp |
|
||||||
|
0000000000403E9B | 48 89 5D B8 | mov qword ptr ss:[rbp-48],rbx |
|
||||||
|
0000000000403E9F | 48 89 6D C0 | mov qword ptr ss:[rbp-40],rbp | <<(16)
|
||||||
|
0000000000403EA3 | 48 89 75 F8 | mov qword ptr ss:[rbp-8],rsi |
|
||||||
|
0000000000403EA7 | 48 89 7D F0 | mov qword ptr ss:[rbp-10],rdi |
|
||||||
|
0000000000403EAB | 4C 89 65 D0 | mov qword ptr ss:[rbp-30],r12 |
|
||||||
|
0000000000403EAF | 4C 89 6D D8 | mov qword ptr ss:[rbp-28],r13 |
|
||||||
|
0000000000403EB3 | 4C 89 75 E0 | mov qword ptr ss:[rbp-20],r14 |
|
||||||
|
0000000000403EB7 | 4C 89 7D E8 | mov qword ptr ss:[rbp-18],r15 |
|
||||||
|
0000000000403EBB | 48 83 EC 20 | sub rsp,20 |
|
||||||
|
0000000000403EBF | 49 BB 18 3F 15 13 FE 7F 00 00 | mov r11,7FFE13153F18 |
|
||||||
|
0000000000403EC9 | 41 FF D3 | call r11 |
|
||||||
|
0000000000403ECC | 48 83 C4 20 | add rsp,20 |
|
||||||
|
|
||||||
|
>>>>>>>>> arm64
|
||||||
|
il2cpp:00000000003DE714 F5 0F 1D F8 STR X21, [SP,#-0x10+var_20]! | << absolute safe
|
||||||
|
il2cpp:00000000003DE718 F4 4F 01 A9 STP X20, X19, [SP,#0x20+var_10] | << may be safe
|
||||||
|
il2cpp:00000000003DE71C FD 7B 02 A9 STP X29, X30, [SP,#0x20+var_s0] |
|
||||||
|
il2cpp:00000000003DE720 FD 83 00 91 ADD X29, SP, #0x20 |
|
||||||
|
il2cpp:00000000003DE724 B5 30 00 B0 ADRP X21, #_ZZ62GameObject_SetActive_mCF1EEF2A314F3AE | << dangerous: relative instruction, can not be overwritten
|
||||||
|
il2cpp:00000000003DE728 A2 56 47 F9 LDR method, [X21,#_ZZ62GameObject_SetActive_mCF] ; |
|
||||||
|
il2cpp:00000000003DE72C F3 03 01 2A MOV W19, W1 |
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MonoHook
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Hook 类,用来 Hook 某个 C# 方法
|
||||||
|
/// </summary>
|
||||||
|
public unsafe class MethodHook
|
||||||
|
{
|
||||||
|
public string tag;
|
||||||
|
public bool isHooked { get; private set; }
|
||||||
|
public bool isPlayModeHook { get; private set; }
|
||||||
|
|
||||||
|
public MethodBase targetMethod { get; private set; } // 需要被hook的目标方法
|
||||||
|
public MethodBase replacementMethod { get; private set; } // 被hook后的替代方法
|
||||||
|
public MethodBase proxyMethod { get; private set; } // 目标方法的代理方法(可以通过此方法调用被hook后的原方法)
|
||||||
|
|
||||||
|
private IntPtr _targetPtr; // 目标方法被 jit 后的地址指针
|
||||||
|
private IntPtr _replacementPtr;
|
||||||
|
private IntPtr _proxyPtr;
|
||||||
|
|
||||||
|
private CodePatcher _codePatcher;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
|
||||||
|
/// <summary>
|
||||||
|
/// call `MethodInfo.MethodHandle.GetFunctionPointer()`
|
||||||
|
/// will visit static class `UnityEditor.IMGUI.Controls.TreeViewGUI.Styles` and invoke its static constructor,
|
||||||
|
/// and init static filed `foldout`, but `GUISKin.current` is null now,
|
||||||
|
/// so we should wait until `GUISKin.current` has a valid value
|
||||||
|
/// </summary>
|
||||||
|
private static FieldInfo s_fi_GUISkin_current;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static MethodHook()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
|
||||||
|
s_fi_GUISkin_current = typeof(GUISkin).GetField("current", BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建一个 Hook
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetMethod">需要替换的目标方法</param>
|
||||||
|
/// <param name="replacementMethod">准备好的替换方法</param>
|
||||||
|
/// <param name="proxyMethod">如果还需要调用原始目标方法,可以通过此参数的方法调用,如果不需要可以填 null</param>
|
||||||
|
public MethodHook(MethodBase targetMethod, MethodBase replacementMethod, MethodBase proxyMethod, string data = "")
|
||||||
|
{
|
||||||
|
this.targetMethod = targetMethod;
|
||||||
|
this.replacementMethod = replacementMethod;
|
||||||
|
this.proxyMethod = proxyMethod;
|
||||||
|
this.tag = data;
|
||||||
|
|
||||||
|
CheckMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Install()
|
||||||
|
{
|
||||||
|
if (LDasm.IsiOS()) // iOS 不支持修改 code 所在区域 page
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (isHooked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
|
||||||
|
if (s_fi_GUISkin_current.GetValue(null) != null)
|
||||||
|
DoInstall();
|
||||||
|
else
|
||||||
|
EditorApplication.update += OnEditorUpdate;
|
||||||
|
#else
|
||||||
|
DoInstall();
|
||||||
|
#endif
|
||||||
|
isPlayModeHook = Application.isPlaying;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Uninstall()
|
||||||
|
{
|
||||||
|
if (!isHooked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_codePatcher.RemovePatch();
|
||||||
|
|
||||||
|
isHooked = false;
|
||||||
|
HookPool.RemoveHooker(targetMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region private
|
||||||
|
private void DoInstall()
|
||||||
|
{
|
||||||
|
if (targetMethod == null || replacementMethod == null)
|
||||||
|
throw new Exception("none of methods targetMethod or replacementMethod can be null");
|
||||||
|
|
||||||
|
HookPool.AddHook(targetMethod, this);
|
||||||
|
|
||||||
|
if (_codePatcher == null)
|
||||||
|
{
|
||||||
|
if (GetFunctionAddr())
|
||||||
|
{
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
UnityEngine.Debug.Log($"Original [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
|
||||||
|
UnityEngine.Debug.Log($"Original [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
|
||||||
|
if(proxyMethod != null)
|
||||||
|
UnityEngine.Debug.Log($"Original [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CreateCodePatcher();
|
||||||
|
_codePatcher.ApplyPatch();
|
||||||
|
|
||||||
|
#if ENABLE_HOOK_DEBUG
|
||||||
|
UnityEngine.Debug.Log($"New [{targetMethod.DeclaringType.Name}.{targetMethod.Name}]: {HookUtils.HexToString(_targetPtr.ToPointer(), 64, -16)}");
|
||||||
|
UnityEngine.Debug.Log($"New [{replacementMethod.DeclaringType.Name}.{replacementMethod.Name}]: {HookUtils.HexToString(_replacementPtr.ToPointer(), 64, -16)}");
|
||||||
|
if(proxyMethod != null)
|
||||||
|
UnityEngine.Debug.Log($"New [{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}]: {HookUtils.HexToString(_proxyPtr.ToPointer(), 64, -16)}");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isHooked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckMethod()
|
||||||
|
{
|
||||||
|
if (targetMethod == null || replacementMethod == null)
|
||||||
|
throw new Exception("MethodHook:targetMethod and replacementMethod and proxyMethod can not be null");
|
||||||
|
|
||||||
|
string methodName = $"{targetMethod.DeclaringType.Name}.{targetMethod.Name}";
|
||||||
|
if (targetMethod.IsAbstract)
|
||||||
|
throw new Exception($"WRANING: you can not hook abstract method [{methodName}]");
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
|
||||||
|
int minMethodBodySize = 10;
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((targetMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != MethodImplAttributes.InternalCall)
|
||||||
|
{
|
||||||
|
int codeSize = targetMethod.GetMethodBody().GetILAsByteArray().Length; // GetMethodBody can not call on il2cpp
|
||||||
|
if (codeSize < minMethodBodySize)
|
||||||
|
UnityEngine.Debug.LogWarning($"WRANING: you can not hook method [{methodName}], cause its method body is too short({codeSize}), will random crash on IL2CPP release mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proxyMethod != null)
|
||||||
|
{
|
||||||
|
methodName = $"{proxyMethod.DeclaringType.Name}.{proxyMethod.Name}";
|
||||||
|
int codeSize = proxyMethod.GetMethodBody().GetILAsByteArray().Length;
|
||||||
|
if (codeSize < minMethodBodySize)
|
||||||
|
UnityEngine.Debug.LogWarning($"WRANING: size of method body[{methodName}] is too short({codeSize}), will random crash on IL2CPP release mode, please fill some dummy code inside");
|
||||||
|
|
||||||
|
if ((proxyMethod.MethodImplementationFlags & MethodImplAttributes.NoOptimization) != MethodImplAttributes.NoOptimization)
|
||||||
|
throw new Exception($"WRANING: method [{methodName}] must has a Attribute `MethodImpl(MethodImplOptions.NoOptimization)` to prevent code call to this optimized by compiler(pass args by shared stack)");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateCodePatcher()
|
||||||
|
{
|
||||||
|
long addrOffset = Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64());
|
||||||
|
|
||||||
|
if(_proxyPtr != IntPtr.Zero)
|
||||||
|
addrOffset = Math.Max(addrOffset, Math.Abs(_targetPtr.ToInt64() - _proxyPtr.ToInt64()));
|
||||||
|
|
||||||
|
if (LDasm.IsARM())
|
||||||
|
{
|
||||||
|
if (IntPtr.Size == 8)
|
||||||
|
_codePatcher = new CodePatcher_arm64_near(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
else if (addrOffset < ((1 << 25) - 1))
|
||||||
|
_codePatcher = new CodePatcher_arm32_near(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
else if (addrOffset < ((1 << 27) - 1))
|
||||||
|
_codePatcher = new CodePatcher_arm32_far(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
else
|
||||||
|
throw new Exception("address of target method and replacement method are too far, can not hook");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IntPtr.Size == 8)
|
||||||
|
{
|
||||||
|
if(addrOffset < 0x7fffffff) // 2G
|
||||||
|
_codePatcher = new CodePatcher_x64_near(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
else
|
||||||
|
_codePatcher = new CodePatcher_x64_far(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_codePatcher = new CodePatcher_x86(_targetPtr, _replacementPtr, _proxyPtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取对应函数jit后的native code的地址
|
||||||
|
/// </summary>
|
||||||
|
private bool GetFunctionAddr()
|
||||||
|
{
|
||||||
|
_targetPtr = GetFunctionAddr(targetMethod);
|
||||||
|
_replacementPtr = GetFunctionAddr(replacementMethod);
|
||||||
|
_proxyPtr = GetFunctionAddr(proxyMethod);
|
||||||
|
|
||||||
|
if (_targetPtr == IntPtr.Zero || _replacementPtr == IntPtr.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (proxyMethod != null && _proxyPtr == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(_replacementPtr == _targetPtr)
|
||||||
|
{
|
||||||
|
throw new Exception($"the addresses of target method {targetMethod.Name} and replacement method {replacementMethod.Name} can not be same");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LDasm.IsThumb(_targetPtr) || LDasm.IsThumb(_replacementPtr))
|
||||||
|
{
|
||||||
|
throw new Exception("does not support thumb arch");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)] // 好像在 IL2CPP 里无效
|
||||||
|
private struct __ForCopy
|
||||||
|
{
|
||||||
|
public long __dummy;
|
||||||
|
public MethodBase method;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 获取方法指令地址
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="method"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private IntPtr GetFunctionAddr(MethodBase method)
|
||||||
|
{
|
||||||
|
if (method == null)
|
||||||
|
return IntPtr.Zero;
|
||||||
|
|
||||||
|
if (!LDasm.IsIL2CPP())
|
||||||
|
return method.MethodHandle.GetFunctionPointer();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// System.Reflection.MonoMethod
|
||||||
|
typedef struct Il2CppReflectionMethod
|
||||||
|
{
|
||||||
|
Il2CppObject object;
|
||||||
|
const MethodInfo *method;
|
||||||
|
Il2CppString *name;
|
||||||
|
Il2CppReflectionType *reftype;
|
||||||
|
} Il2CppReflectionMethod;
|
||||||
|
|
||||||
|
typedef Il2CppClass Il2CppVTable;
|
||||||
|
typedef struct Il2CppObject
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Il2CppClass *klass;
|
||||||
|
Il2CppVTable *vtable;
|
||||||
|
};
|
||||||
|
MonitorData *monitor;
|
||||||
|
} Il2CppObject;
|
||||||
|
|
||||||
|
typedef struct MethodInfo
|
||||||
|
{
|
||||||
|
Il2CppMethodPointer methodPointer; // this is the pointer to native code of method
|
||||||
|
InvokerMethod invoker_method;
|
||||||
|
const char* name;
|
||||||
|
Il2CppClass *klass;
|
||||||
|
const Il2CppType *return_type;
|
||||||
|
const ParameterInfo* parameters;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
__ForCopy __forCopy = new __ForCopy() { method = method };
|
||||||
|
|
||||||
|
long* ptr = &__forCopy.__dummy;
|
||||||
|
ptr++; // addr of _forCopy.method
|
||||||
|
|
||||||
|
IntPtr methodAddr = IntPtr.Zero;
|
||||||
|
if (sizeof(IntPtr) == 8)
|
||||||
|
{
|
||||||
|
long methodDataAddr = *(long*)ptr;
|
||||||
|
byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
|
||||||
|
|
||||||
|
long methodPtr = 0;
|
||||||
|
methodPtr = *(long*)ptrData;
|
||||||
|
methodAddr = new IntPtr(*(long*)methodPtr); // MethodInfo::Il2CppMethodPointer methodPointer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int methodDataAddr = *(int*)ptr;
|
||||||
|
byte* ptrData = (byte*)methodDataAddr + sizeof(IntPtr) * 2; // offset of Il2CppReflectionMethod::const MethodInfo *method;
|
||||||
|
|
||||||
|
int methodPtr = 0;
|
||||||
|
methodPtr = *(int*)ptrData;
|
||||||
|
methodAddr = new IntPtr(*(int*)methodPtr);
|
||||||
|
}
|
||||||
|
return methodAddr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !UNITY_2020_3_OR_NEWER
|
||||||
|
private void OnEditorUpdate()
|
||||||
|
{
|
||||||
|
if (s_fi_GUISkin_current.GetValue(null) != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DoInstall();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
EditorApplication.update -= OnEditorUpdate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bd0b8071cf434d6498160259e3829980
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 259c1cb7fe681f74eb435ab8f268890d
|
guid: 16b9dc031f67b4fe5ad79c230f75768c
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// Utils.cpp
|
||||||
|
// MonoHookUtils_OSX
|
||||||
|
//
|
||||||
|
// Created by Misaka-Mikoto on 2022/8/31.
|
||||||
|
//
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libkern/OSCacheControl.h>
|
||||||
|
|
||||||
|
extern "C"{
|
||||||
|
|
||||||
|
void* memcpy_jit(void* dst, void* src, int32_t size)
|
||||||
|
{
|
||||||
|
pthread_jit_write_protect_np(0);
|
||||||
|
void* ret = memcpy(dst, src, size);
|
||||||
|
pthread_jit_write_protect_np(1);
|
||||||
|
sys_icache_invalidate (dst, size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: b93c6604eb031674b80de14cd4458dc0
|
guid: 56b28b5583a184c669dcb968d175544c
|
||||||
PluginImporter:
|
PluginImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
|
|
@ -42,7 +42,7 @@ PluginImporter:
|
||||||
settings:
|
settings:
|
||||||
CPU: AnyCPU
|
CPU: AnyCPU
|
||||||
DefaultValueInitialized: true
|
DefaultValueInitialized: true
|
||||||
OS: AnyOS
|
OS: OSX
|
||||||
- first:
|
- first:
|
||||||
Standalone: Linux64
|
Standalone: Linux64
|
||||||
second:
|
second:
|
||||||
|
|
@ -54,7 +54,7 @@ PluginImporter:
|
||||||
second:
|
second:
|
||||||
enabled: 0
|
enabled: 0
|
||||||
settings:
|
settings:
|
||||||
CPU: None
|
CPU: ARM64
|
||||||
- first:
|
- first:
|
||||||
Standalone: Win
|
Standalone: Win
|
||||||
second:
|
second:
|
||||||
|
|
@ -67,12 +67,6 @@ PluginImporter:
|
||||||
enabled: 0
|
enabled: 0
|
||||||
settings:
|
settings:
|
||||||
CPU: None
|
CPU: None
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
- first:
|
- first:
|
||||||
iPhone: iOS
|
iPhone: iOS
|
||||||
second:
|
second:
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
clang -shared -undefined dynamic_lookup -o libMonoHookUtils_OSX.dylib Utils.cpp
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 94322e93a1f61b340bdc1d5042dab659
|
guid: 69eeb734e262a0a4fbe0887249198f73
|
||||||
TextScriptImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
assetBundleName:
|
assetBundleName:
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7adba4475cf0bdc4fa7995c0d748f480
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,81 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e092a73910a69894daea44290d7292f6
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude WebGL: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: ARM64
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: OSX
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 31f6a810e38e66f4c832b135770a04bb
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,81 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4adb23596911347faa69537b900c9f5e
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Any
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
Exclude Android: 1
|
||||||
|
Exclude Editor: 0
|
||||||
|
Exclude Linux64: 1
|
||||||
|
Exclude OSXUniversal: 1
|
||||||
|
Exclude WebGL: 1
|
||||||
|
Exclude Win: 1
|
||||||
|
Exclude Win64: 1
|
||||||
|
Exclude iOS: 1
|
||||||
|
- first:
|
||||||
|
Android: Android
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: ARMv7
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: x86_64
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: OSX
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
iPhone: iOS
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
AddToEmbeddedBinaries: false
|
||||||
|
CPU: AnyCPU
|
||||||
|
CompileFlags:
|
||||||
|
FrameworkDependencies:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -14,20 +14,6 @@ namespace HybridCLR.Editor.ABI
|
||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
//public bool IsNative2ManagedByAddress => Type.PorType >= ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE;
|
|
||||||
public bool IsPassToManagedByAddress => Type.GetParamSlotNum() > 1;
|
|
||||||
|
|
||||||
public bool IsPassToNativeByAddress => Type.PorType == ParamOrReturnType.STRUCTURE_AS_REF_PARAM;
|
|
||||||
|
|
||||||
public string Native2ManagedParamValue(PlatformABI canv)
|
|
||||||
{
|
|
||||||
return IsPassToManagedByAddress ? $"(uint64_t)&__arg{Index}" : $"*(uint64_t*)&__arg{Index}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Managed2NativeParamValue(PlatformABI canv)
|
|
||||||
{
|
|
||||||
return IsPassToNativeByAddress ? $"(uint64_t)(localVarBase+argVarIndexs[{Index}])" : $"*({Type.GetTypeName()}*)(localVarBase+argVarIndexs[{Index}])";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReturnInfo
|
public class ReturnInfo
|
||||||
|
|
@ -36,11 +22,6 @@ namespace HybridCLR.Editor.ABI
|
||||||
|
|
||||||
public bool IsVoid => Type.PorType == ParamOrReturnType.VOID;
|
public bool IsVoid => Type.PorType == ParamOrReturnType.VOID;
|
||||||
|
|
||||||
public int GetParamSlotNum(PlatformABI canv)
|
|
||||||
{
|
|
||||||
return Type.GetParamSlotNum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Type.GetTypeName();
|
return Type.GetTypeName();
|
||||||
|
|
|
||||||
|
|
@ -19,21 +19,9 @@ namespace HybridCLR.Editor.ABI
|
||||||
U8,
|
U8,
|
||||||
R4,
|
R4,
|
||||||
R8,
|
R8,
|
||||||
ARM64_HFA_FLOAT_2,
|
I,
|
||||||
VALUE_TYPE_SIZE_LESS_EQUAL_8,
|
U,
|
||||||
I16, // 8 < size <= 16
|
TYPEDBYREF,
|
||||||
STRUCT_NOT_PASS_AS_VALUE, // struct pass not as value
|
STRUCT,
|
||||||
STRUCTURE_AS_REF_PARAM, // size > 16
|
|
||||||
ARM64_HFA_FLOAT_3,
|
|
||||||
ARM64_HFA_FLOAT_4,
|
|
||||||
ARM64_HFA_DOUBLE_2,
|
|
||||||
ARM64_HFA_DOUBLE_3,
|
|
||||||
ARM64_HFA_DOUBLE_4,
|
|
||||||
ARM64_HVA_8,
|
|
||||||
ARM64_HVA_16,
|
|
||||||
STRUCTURE_ALIGN1, // size > 16
|
|
||||||
STRUCTURE_ALIGN2,
|
|
||||||
STRUCTURE_ALIGN4,
|
|
||||||
STRUCTURE_ALIGN8,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,102 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using HybridCLR.Editor.Meta;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.ABI
|
||||||
|
{
|
||||||
|
public class TypeCreator
|
||||||
|
{
|
||||||
|
private readonly Dictionary<TypeSig, TypeInfo> _typeInfoCache = new Dictionary<TypeSig, TypeInfo>(TypeEqualityComparer.Instance);
|
||||||
|
|
||||||
|
private int _nextStructId = 0;
|
||||||
|
|
||||||
|
public TypeInfo CreateTypeInfo(TypeSig type)
|
||||||
|
{
|
||||||
|
type = type.RemovePinnedAndModifiers();
|
||||||
|
if (!_typeInfoCache.TryGetValue(type, out var typeInfo))
|
||||||
|
{
|
||||||
|
typeInfo = CreateTypeInfo0(type);
|
||||||
|
_typeInfoCache.Add(type, typeInfo);
|
||||||
|
}
|
||||||
|
return typeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeInfo CreateTypeInfo0(TypeSig type)
|
||||||
|
{
|
||||||
|
type = type.RemovePinnedAndModifiers();
|
||||||
|
if (type.IsByRef)
|
||||||
|
{
|
||||||
|
return TypeInfo.s_u;
|
||||||
|
}
|
||||||
|
switch (type.ElementType)
|
||||||
|
{
|
||||||
|
case ElementType.Void: return TypeInfo.s_void;
|
||||||
|
case ElementType.Boolean: return TypeInfo.s_u1;
|
||||||
|
case ElementType.I1: return TypeInfo.s_i1;
|
||||||
|
case ElementType.U1: return TypeInfo.s_u1;
|
||||||
|
case ElementType.I2: return TypeInfo.s_i2;
|
||||||
|
case ElementType.Char:
|
||||||
|
case ElementType.U2: return TypeInfo.s_u2;
|
||||||
|
case ElementType.I4: return TypeInfo.s_i4;
|
||||||
|
case ElementType.U4: return TypeInfo.s_u4;
|
||||||
|
case ElementType.I8: return TypeInfo.s_i8;
|
||||||
|
case ElementType.U8: return TypeInfo.s_u8;
|
||||||
|
case ElementType.R4: return TypeInfo.s_r4;
|
||||||
|
case ElementType.R8: return TypeInfo.s_r8;
|
||||||
|
case ElementType.I: return TypeInfo.s_i;
|
||||||
|
case ElementType.U:
|
||||||
|
case ElementType.String:
|
||||||
|
case ElementType.Ptr:
|
||||||
|
case ElementType.ByRef:
|
||||||
|
case ElementType.Class:
|
||||||
|
case ElementType.Array:
|
||||||
|
case ElementType.SZArray:
|
||||||
|
case ElementType.FnPtr:
|
||||||
|
case ElementType.Object:
|
||||||
|
case ElementType.Module:
|
||||||
|
case ElementType.Var:
|
||||||
|
case ElementType.MVar:
|
||||||
|
return TypeInfo.s_u;
|
||||||
|
case ElementType.TypedByRef: return TypeInfo.s_typedByRef;
|
||||||
|
case ElementType.ValueType:
|
||||||
|
{
|
||||||
|
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
|
||||||
|
if (typeDef == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"type:{type} definition could not be found. Please try `HybridCLR/Genergate/LinkXml`, then Build once to generate the AOT dll, and then regenerate the bridge function");
|
||||||
|
}
|
||||||
|
if (typeDef.IsEnum)
|
||||||
|
{
|
||||||
|
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
|
||||||
|
}
|
||||||
|
return CreateValueType(type);
|
||||||
|
}
|
||||||
|
case ElementType.GenericInst:
|
||||||
|
{
|
||||||
|
GenericInstSig gis = (GenericInstSig)type;
|
||||||
|
if (!gis.GenericType.IsValueType)
|
||||||
|
{
|
||||||
|
return TypeInfo.s_u;
|
||||||
|
}
|
||||||
|
TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
|
||||||
|
if (typeDef.IsEnum)
|
||||||
|
{
|
||||||
|
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
|
||||||
|
}
|
||||||
|
return CreateValueType(type);
|
||||||
|
}
|
||||||
|
default: throw new NotSupportedException($"{type.ElementType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected TypeInfo CreateValueType(TypeSig type)
|
||||||
|
{
|
||||||
|
return new TypeInfo(ParamOrReturnType.STRUCT, type, _nextStructId++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0b1df5760b488fa43a68843c46fda63a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using HybridCLR.Editor.Meta;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public class HFATypeInfo
|
|
||||||
{
|
|
||||||
public TypeSig Type { get; set; }
|
|
||||||
|
|
||||||
public int Count { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TypeCreatorArm64 : TypeCreatorBase
|
|
||||||
{
|
|
||||||
public override bool IsArch32 => false;
|
|
||||||
|
|
||||||
public override bool IsSupportHFA => true;
|
|
||||||
|
|
||||||
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
|
|
||||||
{
|
|
||||||
if (!type.IsGeneralValueType)
|
|
||||||
{
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
int typeSize = type.Size;
|
|
||||||
if (typeSize <= 8)
|
|
||||||
{
|
|
||||||
return TypeInfo.s_i8;
|
|
||||||
}
|
|
||||||
if (typeSize <= 16)
|
|
||||||
{
|
|
||||||
return TypeInfo.s_i16;
|
|
||||||
}
|
|
||||||
if (returnType)
|
|
||||||
{
|
|
||||||
return type.PorType != ParamOrReturnType.STRUCTURE_ALIGN1 ? new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, typeSize) : type;
|
|
||||||
}
|
|
||||||
return TypeInfo.s_ref;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,298 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using HybridCLR.Editor.Meta;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public abstract class TypeCreatorBase
|
|
||||||
{
|
|
||||||
public abstract bool IsArch32 { get; }
|
|
||||||
|
|
||||||
public virtual bool IsSupportHFA => false;
|
|
||||||
|
|
||||||
public virtual bool IsSupportSingletonStruct => false;
|
|
||||||
|
|
||||||
public TypeInfo GetNativeIntTypeInfo() => IsArch32 ? TypeInfo.s_i4 : TypeInfo.s_i8;
|
|
||||||
|
|
||||||
public ValueTypeSizeAligmentCalculator Calculator => IsArch32 ? ValueTypeSizeAligmentCalculator.Caculator32 : ValueTypeSizeAligmentCalculator.Caculator64;
|
|
||||||
|
|
||||||
|
|
||||||
private readonly Dictionary<TypeSig, (int, int)> _typeSizeCache = new Dictionary<TypeSig, (int, int)>(TypeEqualityComparer.Instance);
|
|
||||||
|
|
||||||
public (int Size, int Aligment) ComputeSizeAndAligment(TypeSig t)
|
|
||||||
{
|
|
||||||
if (_typeSizeCache.TryGetValue(t, out var sizeAndAligment))
|
|
||||||
{
|
|
||||||
return sizeAndAligment;
|
|
||||||
}
|
|
||||||
sizeAndAligment = Calculator.SizeAndAligmentOf(t);
|
|
||||||
_typeSizeCache.Add(t, sizeAndAligment);
|
|
||||||
return sizeAndAligment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeInfo CreateTypeInfo(TypeSig type)
|
|
||||||
{
|
|
||||||
type = type.RemovePinnedAndModifiers();
|
|
||||||
if (type.IsByRef)
|
|
||||||
{
|
|
||||||
return GetNativeIntTypeInfo();
|
|
||||||
}
|
|
||||||
switch (type.ElementType)
|
|
||||||
{
|
|
||||||
case ElementType.Void: return TypeInfo.s_void;
|
|
||||||
case ElementType.Boolean: return TypeInfo.s_u1;
|
|
||||||
case ElementType.I1: return TypeInfo.s_i1;
|
|
||||||
case ElementType.U1: return TypeInfo.s_u1;
|
|
||||||
case ElementType.I2: return TypeInfo.s_i2;
|
|
||||||
case ElementType.Char:
|
|
||||||
case ElementType.U2: return TypeInfo.s_u2;
|
|
||||||
case ElementType.I4: return TypeInfo.s_i4;
|
|
||||||
case ElementType.U4: return TypeInfo.s_u4;
|
|
||||||
case ElementType.I8: return TypeInfo.s_i8;
|
|
||||||
case ElementType.U8: return TypeInfo.s_u8;
|
|
||||||
case ElementType.R4: return TypeInfo.s_r4;
|
|
||||||
case ElementType.R8: return TypeInfo.s_r8;
|
|
||||||
case ElementType.U: return IsArch32 ? TypeInfo.s_u4 : TypeInfo.s_u8;
|
|
||||||
case ElementType.I:
|
|
||||||
case ElementType.String:
|
|
||||||
case ElementType.Ptr:
|
|
||||||
case ElementType.ByRef:
|
|
||||||
case ElementType.Class:
|
|
||||||
case ElementType.Array:
|
|
||||||
case ElementType.SZArray:
|
|
||||||
case ElementType.FnPtr:
|
|
||||||
case ElementType.Object:
|
|
||||||
case ElementType.Module:
|
|
||||||
case ElementType.Var:
|
|
||||||
case ElementType.MVar:
|
|
||||||
return GetNativeIntTypeInfo();
|
|
||||||
case ElementType.TypedByRef: return CreateValueType(type);
|
|
||||||
case ElementType.ValueType:
|
|
||||||
{
|
|
||||||
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDef();
|
|
||||||
if (typeDef == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"type:{type} 未能找到定义。请尝试 `HybridCLR/Genergate/LinkXml`,然后Build一次生成AOT dll,再重新生成桥接函数");
|
|
||||||
}
|
|
||||||
if (typeDef.IsEnum)
|
|
||||||
{
|
|
||||||
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
|
|
||||||
}
|
|
||||||
return CreateValueType(type);
|
|
||||||
}
|
|
||||||
case ElementType.GenericInst:
|
|
||||||
{
|
|
||||||
GenericInstSig gis = (GenericInstSig)type;
|
|
||||||
if (!gis.GenericType.IsValueType)
|
|
||||||
{
|
|
||||||
return GetNativeIntTypeInfo();
|
|
||||||
}
|
|
||||||
TypeDef typeDef = gis.GenericType.ToTypeDefOrRef().ResolveTypeDef();
|
|
||||||
if (typeDef.IsEnum)
|
|
||||||
{
|
|
||||||
return CreateTypeInfo(typeDef.GetEnumUnderlyingType());
|
|
||||||
}
|
|
||||||
return CreateValueType(type);
|
|
||||||
}
|
|
||||||
default: throw new NotSupportedException($"{type.ElementType}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsNotHFAFastCheck(int typeSize)
|
|
||||||
{
|
|
||||||
return typeSize != 8 && typeSize != 12 && typeSize != 16 && typeSize != 24 && typeSize != 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ComputHFATypeInfo0(TypeSig type, HFATypeInfo typeInfo)
|
|
||||||
{
|
|
||||||
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow();
|
|
||||||
|
|
||||||
List<TypeSig> klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList();
|
|
||||||
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
|
||||||
|
|
||||||
var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|
||||||
foreach (FieldDef field in fields)
|
|
||||||
{
|
|
||||||
if (field.IsStatic)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
|
||||||
switch (ftype.ElementType)
|
|
||||||
{
|
|
||||||
case ElementType.R4:
|
|
||||||
case ElementType.R8:
|
|
||||||
{
|
|
||||||
if (ftype == typeInfo.Type || typeInfo.Type == null)
|
|
||||||
{
|
|
||||||
typeInfo.Type = ftype;
|
|
||||||
++typeInfo.Count;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElementType.ValueType:
|
|
||||||
{
|
|
||||||
if (!ComputHFATypeInfo0(ftype, typeInfo))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElementType.GenericInst:
|
|
||||||
{
|
|
||||||
if (!ftype.IsValueType || !ComputHFATypeInfo0(ftype, typeInfo))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return typeInfo.Count <= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ComputHFATypeInfo(TypeSig type, int typeSize, out HFATypeInfo typeInfo)
|
|
||||||
{
|
|
||||||
typeInfo = new HFATypeInfo();
|
|
||||||
if (IsNotHFAFastCheck(typeSize))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool ok = ComputHFATypeInfo0(type, typeInfo);
|
|
||||||
if (ok && typeInfo.Count >= 2 && typeInfo.Count <= 4)
|
|
||||||
{
|
|
||||||
int fieldSize = typeInfo.Type.ElementType == ElementType.R4 ? 4 : 8;
|
|
||||||
return typeSize == fieldSize * typeInfo.Count;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryComputSingletonStruct(TypeSig type, out SingletonStruct result)
|
|
||||||
{
|
|
||||||
result = new SingletonStruct();
|
|
||||||
return TryComputSingletonStruct0(type, result) && result.Type != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool TryComputSingletonStruct0(TypeSig type, SingletonStruct result)
|
|
||||||
{
|
|
||||||
TypeDef typeDef = type.ToTypeDefOrRef().ResolveTypeDefThrow();
|
|
||||||
if (typeDef.IsEnum)
|
|
||||||
{
|
|
||||||
if (result.Type == null)
|
|
||||||
{
|
|
||||||
result.Type = typeDef.GetEnumUnderlyingType();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<TypeSig> klassInst = type.ToGenericInstSig()?.GenericArguments?.ToList();
|
|
||||||
GenericArgumentContext ctx = klassInst != null ? new GenericArgumentContext(klassInst, null) : null;
|
|
||||||
|
|
||||||
var fields = typeDef.Fields;// typeDef.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
|
||||||
foreach (FieldDef field in fields)
|
|
||||||
{
|
|
||||||
if (field.IsStatic)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TypeSig ftype = ctx != null ? MetaUtil.Inflate(field.FieldType, ctx) : field.FieldType;
|
|
||||||
|
|
||||||
switch (ftype.ElementType)
|
|
||||||
{
|
|
||||||
case ElementType.TypedByRef: return false;
|
|
||||||
case ElementType.ValueType:
|
|
||||||
{
|
|
||||||
if (!TryComputSingletonStruct0(ftype, result))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ElementType.GenericInst:
|
|
||||||
{
|
|
||||||
if (!ftype.IsValueType)
|
|
||||||
{
|
|
||||||
goto default;
|
|
||||||
}
|
|
||||||
if (!TryComputSingletonStruct0(ftype, result))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
if (result.Type != null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
result.Type = ftype;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static TypeInfo CreateGeneralValueType(TypeSig type, int size, int aligment)
|
|
||||||
{
|
|
||||||
System.Diagnostics.Debug.Assert(size % aligment == 0);
|
|
||||||
switch (aligment)
|
|
||||||
{
|
|
||||||
case 1: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, size);
|
|
||||||
case 2: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN2, size);
|
|
||||||
case 4: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN4, size);
|
|
||||||
case 8: return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN8, size);
|
|
||||||
default: throw new NotSupportedException($"type:{type} not support aligment:{aligment}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TypeInfo CreateValueType(TypeSig type)
|
|
||||||
{
|
|
||||||
(int typeSize, int typeAligment) = ComputeSizeAndAligment(type);
|
|
||||||
if (IsSupportHFA && ComputHFATypeInfo(type, typeSize, out HFATypeInfo hfaTypeInfo))
|
|
||||||
{
|
|
||||||
bool isFloat = hfaTypeInfo.Type.ElementType == ElementType.R4;
|
|
||||||
switch (hfaTypeInfo.Count)
|
|
||||||
{
|
|
||||||
case 2: return isFloat ? TypeInfo.s_vf2 : TypeInfo.s_vd2;
|
|
||||||
case 3: return isFloat ? TypeInfo.s_vf3 : TypeInfo.s_vd3;
|
|
||||||
case 4: return isFloat ? TypeInfo.s_vf4 : TypeInfo.s_vd4;
|
|
||||||
default: throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//else if(IsSupportSingletonStruct && TryComputSingletonStruct(type, out var ssTypeInfo))
|
|
||||||
//{
|
|
||||||
// return CreateTypeInfo(ssTypeInfo.Type);
|
|
||||||
//}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 64位下结构体内存对齐规则是一样的
|
|
||||||
return CreateGeneralValueType(type, typeSize, typeAligment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected abstract TypeInfo OptimizeSigType(TypeInfo type, bool returnType);
|
|
||||||
|
|
||||||
public virtual void OptimizeMethod(MethodDesc method)
|
|
||||||
{
|
|
||||||
method.TransfromSigTypes(OptimizeSigType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public static class TypeCreatorFactory
|
|
||||||
{
|
|
||||||
public static TypeCreatorBase CreateTypeCreator(PlatformABI abi)
|
|
||||||
{
|
|
||||||
switch(abi)
|
|
||||||
{
|
|
||||||
case PlatformABI.Arm64: return new TypeCreatorArm64();
|
|
||||||
case PlatformABI.Universal32: return new TypeCreatorUniversal32();
|
|
||||||
case PlatformABI.Universal64: return new TypeCreatorUniversal64();
|
|
||||||
case PlatformABI.WebGL32: return new TypeCreatorWebGL32();
|
|
||||||
default: throw new NotSupportedException(abi.ToString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public class TypeCreatorUniversal32 : TypeCreatorBase
|
|
||||||
{
|
|
||||||
public override bool IsArch32 => true;
|
|
||||||
|
|
||||||
public override bool IsSupportHFA => false;
|
|
||||||
|
|
||||||
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
|
|
||||||
{
|
|
||||||
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)
|
|
||||||
{
|
|
||||||
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public class TypeCreatorUniversal64 : TypeCreatorBase
|
|
||||||
{
|
|
||||||
public override bool IsArch32 => false;
|
|
||||||
|
|
||||||
public override bool IsSupportHFA => true;
|
|
||||||
|
|
||||||
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
|
|
||||||
{
|
|
||||||
if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN8)
|
|
||||||
{
|
|
||||||
return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 7867dfe20d27e324e90bc13b9d4f05bb
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
using dnlib.DotNet;
|
|
||||||
using HybridCLR.Editor.Meta;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.ABI
|
|
||||||
{
|
|
||||||
public class SingletonStruct
|
|
||||||
{
|
|
||||||
public TypeSig Type { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TypeCreatorWebGL32 : TypeCreatorBase
|
|
||||||
{
|
|
||||||
public override bool IsArch32 => true;
|
|
||||||
|
|
||||||
public override bool IsSupportHFA => false;
|
|
||||||
|
|
||||||
public override bool IsSupportSingletonStruct => true;
|
|
||||||
|
|
||||||
|
|
||||||
protected override TypeInfo OptimizeSigType(TypeInfo type, bool returnType)
|
|
||||||
{
|
|
||||||
//if (type.PorType > ParamOrReturnType.STRUCTURE_ALIGN1 && type.PorType <= ParamOrReturnType.STRUCTURE_ALIGN4)
|
|
||||||
//{
|
|
||||||
// return new TypeInfo(ParamOrReturnType.STRUCTURE_ALIGN1, type.Size);
|
|
||||||
//}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 4790a87aacda1a14d813570e9e0f35ca
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using dnlib.DotNet;
|
using dnlib.DotNet;
|
||||||
|
using HybridCLR.Editor.Meta;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
@ -20,37 +21,34 @@ namespace HybridCLR.Editor.ABI
|
||||||
public static readonly TypeInfo s_u8 = new TypeInfo(ParamOrReturnType.U8);
|
public static readonly TypeInfo s_u8 = new TypeInfo(ParamOrReturnType.U8);
|
||||||
public static readonly TypeInfo s_r4 = new TypeInfo(ParamOrReturnType.R4);
|
public static readonly TypeInfo s_r4 = new TypeInfo(ParamOrReturnType.R4);
|
||||||
public static readonly TypeInfo s_r8 = new TypeInfo(ParamOrReturnType.R8);
|
public static readonly TypeInfo s_r8 = new TypeInfo(ParamOrReturnType.R8);
|
||||||
public static readonly TypeInfo s_i16 = new TypeInfo(ParamOrReturnType.I16);
|
public static readonly TypeInfo s_i = new TypeInfo(ParamOrReturnType.I);
|
||||||
public static readonly TypeInfo s_ref = new TypeInfo(ParamOrReturnType.STRUCTURE_AS_REF_PARAM);
|
public static readonly TypeInfo s_u = new TypeInfo(ParamOrReturnType.U);
|
||||||
|
public static readonly TypeInfo s_typedByRef = new TypeInfo(ParamOrReturnType.TYPEDBYREF);
|
||||||
|
|
||||||
public static readonly TypeInfo s_vf2 = new TypeInfo(ParamOrReturnType.ARM64_HFA_FLOAT_2);
|
public const string strTypedByRef = "typedbyref";
|
||||||
public static readonly TypeInfo s_vf3 = new TypeInfo(ParamOrReturnType.ARM64_HFA_FLOAT_3);
|
|
||||||
public static readonly TypeInfo s_vf4 = new TypeInfo(ParamOrReturnType.ARM64_HFA_FLOAT_4);
|
|
||||||
public static readonly TypeInfo s_vd2 = new TypeInfo(ParamOrReturnType.ARM64_HFA_DOUBLE_2);
|
|
||||||
public static readonly TypeInfo s_vd3 = new TypeInfo(ParamOrReturnType.ARM64_HFA_DOUBLE_3);
|
|
||||||
public static readonly TypeInfo s_vd4 = new TypeInfo(ParamOrReturnType.ARM64_HFA_DOUBLE_4);
|
|
||||||
|
|
||||||
public TypeInfo(ParamOrReturnType portype)
|
public TypeInfo(ParamOrReturnType portype, TypeSig klass = null, int typeId = 0)
|
||||||
{
|
{
|
||||||
PorType = portype;
|
PorType = portype;
|
||||||
Size = 0;
|
Klass = klass;
|
||||||
}
|
_typeId = typeId;
|
||||||
|
|
||||||
public TypeInfo(ParamOrReturnType portype, int size)
|
|
||||||
{
|
|
||||||
PorType = portype;
|
|
||||||
Size = size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParamOrReturnType PorType { get; }
|
public ParamOrReturnType PorType { get; }
|
||||||
|
|
||||||
public bool IsGeneralValueType => PorType >= ParamOrReturnType.STRUCTURE_ALIGN1 && PorType <= ParamOrReturnType.STRUCTURE_ALIGN8;
|
public TypeSig Klass { get; }
|
||||||
|
|
||||||
public int Size { get; }
|
public bool IsStruct => PorType == ParamOrReturnType.STRUCT;
|
||||||
|
|
||||||
|
public bool IsPrimitiveType => PorType <= ParamOrReturnType.U;
|
||||||
|
|
||||||
|
private readonly int _typeId;
|
||||||
|
|
||||||
|
public int TypeId => _typeId;
|
||||||
|
|
||||||
public bool Equals(TypeInfo other)
|
public bool Equals(TypeInfo other)
|
||||||
{
|
{
|
||||||
return PorType == other.PorType && Size == other.Size;
|
return PorType == other.PorType && TypeEqualityComparer.Instance.Equals(Klass, other.Klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
|
|
@ -60,7 +58,12 @@ namespace HybridCLR.Editor.ABI
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return (int)PorType * 23 + Size;
|
return (int)PorType * 23 + (Klass != null ? TypeEqualityComparer.Instance.GetHashCode(Klass) : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool NeedExpandValue()
|
||||||
|
{
|
||||||
|
return PorType >= ParamOrReturnType.I1 && PorType <= ParamOrReturnType.U2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string CreateSigName()
|
public string CreateSigName()
|
||||||
|
|
@ -78,18 +81,10 @@ namespace HybridCLR.Editor.ABI
|
||||||
case ParamOrReturnType.U8: return "u8";
|
case ParamOrReturnType.U8: return "u8";
|
||||||
case ParamOrReturnType.R4: return "r4";
|
case ParamOrReturnType.R4: return "r4";
|
||||||
case ParamOrReturnType.R8: return "r8";
|
case ParamOrReturnType.R8: return "r8";
|
||||||
case ParamOrReturnType.I16: return "i16";
|
case ParamOrReturnType.I: return "i";
|
||||||
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "sr";
|
case ParamOrReturnType.U: return "u";
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "vf2";
|
case ParamOrReturnType.TYPEDBYREF: return strTypedByRef;
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "vf3";
|
case ParamOrReturnType.STRUCT: return $"s{_typeId}";
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "vf4";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "vd2";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "vd3";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "vd4";
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN1: return "S" + Size;
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN2: return "A" + Size;
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN4: return "B" + Size;
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN8: return "C" + Size;
|
|
||||||
default: throw new NotSupportedException(PorType.ToString());
|
default: throw new NotSupportedException(PorType.ToString());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -109,46 +104,13 @@ namespace HybridCLR.Editor.ABI
|
||||||
case ParamOrReturnType.U8: return "uint64_t";
|
case ParamOrReturnType.U8: return "uint64_t";
|
||||||
case ParamOrReturnType.R4: return "float";
|
case ParamOrReturnType.R4: return "float";
|
||||||
case ParamOrReturnType.R8: return "double";
|
case ParamOrReturnType.R8: return "double";
|
||||||
case ParamOrReturnType.I16: return "ValueTypeSize16";
|
case ParamOrReturnType.I: return "intptr_t";
|
||||||
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return "uint64_t";
|
case ParamOrReturnType.U: return "uintptr_t";
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_2: return "HtVector2f";
|
case ParamOrReturnType.TYPEDBYREF: return "Il2CppTypedRef";
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return "HtVector3f";
|
case ParamOrReturnType.STRUCT: return $"__struct_{_typeId}__";
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return "HtVector4f";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return "HtVector2d";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return "HtVector3d";
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return "HtVector4d";
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN1: return $"ValueTypeSize<{Size}>";
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN2: return $"ValueTypeSizeAlign2<{Size}>";
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN4: return $"ValueTypeSizeAlign4<{Size}>";
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN8: return $"ValueTypeSizeAlign8<{Size}>";
|
|
||||||
default: throw new NotImplementedException(PorType.ToString());
|
default: throw new NotImplementedException(PorType.ToString());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
public int GetParamSlotNum()
|
|
||||||
{
|
|
||||||
switch (PorType)
|
|
||||||
{
|
|
||||||
case ParamOrReturnType.VOID: return 0;
|
|
||||||
case ParamOrReturnType.I16: return 2;
|
|
||||||
case ParamOrReturnType.STRUCTURE_AS_REF_PARAM: return 1;
|
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_3: return 2;
|
|
||||||
case ParamOrReturnType.ARM64_HFA_FLOAT_4: return 2;
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_2: return 2;
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_3: return 3;
|
|
||||||
case ParamOrReturnType.ARM64_HFA_DOUBLE_4: return 4;
|
|
||||||
case ParamOrReturnType.ARM64_HVA_8:
|
|
||||||
case ParamOrReturnType.ARM64_HVA_16: throw new NotSupportedException();
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN1:
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN2:
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN4:
|
|
||||||
case ParamOrReturnType.STRUCTURE_ALIGN8: return (Size + 7) / 8;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
Debug.Assert(PorType < ParamOrReturnType.STRUCT_NOT_PASS_AS_VALUE);
|
|
||||||
Debug.Assert(Size <= 8);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
using dnlib.DotNet;
|
||||||
|
using dnlib.DotNet.Writer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.AOT
|
||||||
|
{
|
||||||
|
public class AOTAssemblyMetadataStripper
|
||||||
|
{
|
||||||
|
public static byte[] Strip(byte[] assemblyBytes)
|
||||||
|
{
|
||||||
|
var context = ModuleDef.CreateModuleContext();
|
||||||
|
var readerOption = new ModuleCreationOptions(context)
|
||||||
|
{
|
||||||
|
Runtime = CLRRuntimeReaderKind.Mono
|
||||||
|
};
|
||||||
|
var mod = ModuleDefMD.Load(assemblyBytes, readerOption);
|
||||||
|
// remove all resources
|
||||||
|
mod.Resources.Clear();
|
||||||
|
foreach (var type in mod.GetTypes())
|
||||||
|
{
|
||||||
|
if (type.HasGenericParameters)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach (var method in type.Methods)
|
||||||
|
{
|
||||||
|
if (!method.HasBody || method.HasGenericParameters)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
method.Body = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var writer = new System.IO.MemoryStream();
|
||||||
|
var options = new ModuleWriterOptions(mod);
|
||||||
|
options.MetadataOptions.Flags |= MetadataFlags.PreserveRids;
|
||||||
|
mod.Write(writer, options);
|
||||||
|
writer.Flush();
|
||||||
|
return writer.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Strip(string originalAssemblyPath, string strippedAssemblyPath)
|
||||||
|
{
|
||||||
|
byte[] originDllBytes = System.IO.File.ReadAllBytes(originalAssemblyPath);
|
||||||
|
byte[] strippedDllBytes = Strip(originDllBytes);
|
||||||
|
UnityEngine.Debug.Log($"aot dll:{originalAssemblyPath}, length: {originDllBytes.Length} -> {strippedDllBytes.Length}, stripping rate:{(originDllBytes.Length - strippedDllBytes.Length)/(double)originDllBytes.Length} ");
|
||||||
|
Directory.CreateDirectory(System.IO.Path.GetDirectoryName(strippedAssemblyPath));
|
||||||
|
System.IO.File.WriteAllBytes(strippedAssemblyPath, strippedDllBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7e9e6a048682dcb4fab806251411f29f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -17,12 +17,16 @@ namespace HybridCLR.Editor.AOT
|
||||||
public AssemblyReferenceDeepCollector Collector { get; set; }
|
public AssemblyReferenceDeepCollector Collector { get; set; }
|
||||||
|
|
||||||
public int MaxIterationCount { get; set; }
|
public int MaxIterationCount { get; set; }
|
||||||
|
|
||||||
|
public bool ComputeAotAssembly { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly int _maxInterationCount;
|
private readonly int _maxInterationCount;
|
||||||
|
|
||||||
private readonly AssemblyReferenceDeepCollector _assemblyCollector;
|
private readonly AssemblyReferenceDeepCollector _assemblyCollector;
|
||||||
|
|
||||||
|
private readonly bool _computeAotAssembly;
|
||||||
|
|
||||||
private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
|
private readonly HashSet<GenericClass> _genericTypes = new HashSet<GenericClass>();
|
||||||
private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
|
private readonly HashSet<GenericMethod> _genericMethods = new HashSet<GenericMethod>();
|
||||||
|
|
||||||
|
|
@ -47,6 +51,7 @@ namespace HybridCLR.Editor.AOT
|
||||||
{
|
{
|
||||||
_assemblyCollector = options.Collector;
|
_assemblyCollector = options.Collector;
|
||||||
_maxInterationCount = options.MaxIterationCount;
|
_maxInterationCount = options.MaxIterationCount;
|
||||||
|
_computeAotAssembly = options.ComputeAotAssembly;
|
||||||
_methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
|
_methodReferenceAnalyzer = new MethodReferenceAnalyzer(this.OnNewMethod);
|
||||||
_hotUpdateAssemblyFiles = new HashSet<string>(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll"));
|
_hotUpdateAssemblyFiles = new HashSet<string>(options.Collector.GetRootAssemblyNames().Select(assName => assName + ".dll"));
|
||||||
}
|
}
|
||||||
|
|
@ -58,20 +63,20 @@ namespace HybridCLR.Editor.AOT
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gc = gc.ToGenericShare();
|
gc = gc.ToGenericShare();
|
||||||
if (_genericTypes.Add(gc) && NeedWalk(gc.Type))
|
if (_genericTypes.Add(gc) && NeedWalk(null, gc.Type))
|
||||||
{
|
{
|
||||||
WalkType(gc);
|
WalkType(gc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool NeedWalk(TypeDef type)
|
private bool NeedWalk(MethodDef callFrom, TypeDef type)
|
||||||
{
|
{
|
||||||
return _hotUpdateAssemblyFiles.Contains(type.Module.Name);
|
return _hotUpdateAssemblyFiles.Contains(type.Module.Name) || callFrom == null || callFrom.HasGenericParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAotType(TypeDef type)
|
private bool IsAotType(TypeDef type)
|
||||||
{
|
{
|
||||||
return !_hotUpdateAssemblyFiles.Contains(type.Module.Name);
|
return _computeAotAssembly || !_hotUpdateAssemblyFiles.Contains(type.Module.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsAotGenericMethod(MethodDef method)
|
private bool IsAotGenericMethod(MethodDef method)
|
||||||
|
|
@ -79,13 +84,13 @@ namespace HybridCLR.Editor.AOT
|
||||||
return IsAotType(method.DeclaringType) && method.HasGenericParameters;
|
return IsAotType(method.DeclaringType) && method.HasGenericParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnNewMethod(GenericMethod method)
|
private void OnNewMethod(MethodDef methodDef, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst, GenericMethod method)
|
||||||
{
|
{
|
||||||
if(method == null)
|
if(method == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_genericMethods.Add(method) && NeedWalk(method.Method.DeclaringType))
|
if (NeedWalk(methodDef, method.Method.DeclaringType) && _genericMethods.Add(method))
|
||||||
{
|
{
|
||||||
_newMethods.Add(method);
|
_newMethods.Add(method);
|
||||||
}
|
}
|
||||||
|
|
@ -101,7 +106,7 @@ namespace HybridCLR.Editor.AOT
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_genericMethods.Add(method) && NeedWalk(method.Method.DeclaringType))
|
if (NeedWalk(null, method.Method.DeclaringType) && _genericMethods.Add(method))
|
||||||
{
|
{
|
||||||
_newMethods.Add(method);
|
_newMethods.Add(method);
|
||||||
}
|
}
|
||||||
|
|
@ -157,9 +162,9 @@ namespace HybridCLR.Editor.AOT
|
||||||
for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
|
for (uint rid = 1, n = ass.Metadata.TablesStream.TypeSpecTable.Rows; rid <= n; rid++)
|
||||||
{
|
{
|
||||||
var ts = ass.ResolveTypeSpec(rid);
|
var ts = ass.ResolveTypeSpec(rid);
|
||||||
if (!ts.ContainsGenericParameter)
|
|
||||||
{
|
|
||||||
var cs = GenericClass.ResolveClass(ts, null)?.ToGenericShare();
|
var cs = GenericClass.ResolveClass(ts, null)?.ToGenericShare();
|
||||||
|
if (cs != null)
|
||||||
|
{
|
||||||
TryAddAndWalkGenericType(cs);
|
TryAddAndWalkGenericType(cs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -167,10 +172,6 @@ namespace HybridCLR.Editor.AOT
|
||||||
for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
|
for (uint rid = 1, n = ass.Metadata.TablesStream.MethodSpecTable.Rows; rid <= n; rid++)
|
||||||
{
|
{
|
||||||
var ms = ass.ResolveMethodSpec(rid);
|
var ms = ass.ResolveMethodSpec(rid);
|
||||||
if (ms.DeclaringType.ContainsGenericParameter || ms.GenericInstMethodSig.ContainsGenericParameter)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
|
var gm = GenericMethod.ResolveMethod(ms, null)?.ToGenericShare();
|
||||||
TryAddMethodNotWalkType(gm);
|
TryAddMethodNotWalkType(gm);
|
||||||
}
|
}
|
||||||
|
|
@ -195,11 +196,29 @@ namespace HybridCLR.Editor.AOT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsNotShareableAOTGenericType(TypeDef typeDef)
|
||||||
|
{
|
||||||
|
if (!IsAotType(typeDef))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return typeDef.GenericParameters.Any(c => !c.HasReferenceTypeConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsNotShareableAOTGenericMethod(MethodDef method)
|
||||||
|
{
|
||||||
|
if (!IsAotGenericMethod(method))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return method.GenericParameters.Concat(method.DeclaringType.GenericParameters).Any(c => !c.HasReferenceTypeConstraint);
|
||||||
|
}
|
||||||
|
|
||||||
private void FilterAOTGenericTypeAndMethods()
|
private void FilterAOTGenericTypeAndMethods()
|
||||||
{
|
{
|
||||||
ConstraintContext cc = this.ConstraintContext;
|
ConstraintContext cc = this.ConstraintContext;
|
||||||
AotGenericTypes.AddRange(_genericTypes.Where(type => IsAotType(type.Type)).Select(gc => cc.ApplyConstraints(gc)));
|
AotGenericTypes.AddRange(_genericTypes.Where(type => IsNotShareableAOTGenericType(type.Type)).Select(gc => cc.ApplyConstraints(gc)));
|
||||||
AotGenericMethods.AddRange(_genericMethods.Where(method => IsAotGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm)));
|
AotGenericMethods.AddRange(_genericMethods.Where(method => IsNotShareableAOTGenericMethod(method.Method)).Select(gm => cc.ApplyConstraints(gm)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
@ -11,27 +12,90 @@ namespace HybridCLR.Editor.AOT
|
||||||
{
|
{
|
||||||
public class GenericReferenceWriter
|
public class GenericReferenceWriter
|
||||||
{
|
{
|
||||||
|
private static readonly Dictionary<Type, string> _typeNameMapping = new Dictionary<Type, string>
|
||||||
|
{
|
||||||
|
{typeof(bool), "bool" },
|
||||||
|
{typeof(byte), "byte" },
|
||||||
|
{typeof(sbyte), "sbyte" },
|
||||||
|
{typeof(short), "short" },
|
||||||
|
{typeof(ushort), "ushort" },
|
||||||
|
{typeof(int), "int" },
|
||||||
|
{typeof(uint), "uint" },
|
||||||
|
{typeof(long), "long" },
|
||||||
|
{typeof(ulong), "ulong" },
|
||||||
|
{typeof(float), "float" },
|
||||||
|
{typeof(double), "double" },
|
||||||
|
{typeof(object), "object" },
|
||||||
|
{typeof(string), "string" },
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<string, string> _typeSimpleNameMapping = new Dictionary<string, string>();
|
||||||
|
private readonly Regex _systemTypePattern;
|
||||||
|
private readonly Regex _genericPattern = new Regex(@"`\d+");
|
||||||
|
|
||||||
|
public GenericReferenceWriter()
|
||||||
|
{
|
||||||
|
foreach (var e in _typeNameMapping)
|
||||||
|
{
|
||||||
|
_typeSimpleNameMapping.Add(e.Key.FullName, e.Value);
|
||||||
|
}
|
||||||
|
_systemTypePattern = new Regex(string.Join("|", _typeSimpleNameMapping.Keys.Select (k => $@"\b{Regex.Escape(k)}\b")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PrettifyTypeSig(string typeSig)
|
||||||
|
{
|
||||||
|
string s = _genericPattern.Replace(typeSig, "").Replace('/', '.');
|
||||||
|
return _systemTypePattern.Replace(s, m => _typeSimpleNameMapping[m.Groups[0].Value]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PrettifyMethodSig(string methodSig)
|
||||||
|
{
|
||||||
|
string s = PrettifyTypeSig(methodSig).Replace("::", ".");
|
||||||
|
if (s.Contains(".ctor("))
|
||||||
|
{
|
||||||
|
s = "new " + s.Replace(".ctor(", "(");
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
public void Write(List<GenericClass> types, List<GenericMethod> methods, string outputFile)
|
public void Write(List<GenericClass> types, List<GenericMethod> methods, string outputFile)
|
||||||
{
|
{
|
||||||
string parentDir = Directory.GetParent(outputFile).FullName;
|
string parentDir = Directory.GetParent(outputFile).FullName;
|
||||||
Directory.CreateDirectory(parentDir);
|
Directory.CreateDirectory(parentDir);
|
||||||
|
|
||||||
List<string> codes = new List<string>();
|
List<string> codes = new List<string>();
|
||||||
|
codes.Add("using System.Collections.Generic;");
|
||||||
codes.Add("public class AOTGenericReferences : UnityEngine.MonoBehaviour");
|
codes.Add("public class AOTGenericReferences : UnityEngine.MonoBehaviour");
|
||||||
codes.Add("{");
|
codes.Add("{");
|
||||||
|
|
||||||
|
codes.Add("");
|
||||||
|
codes.Add("\t// {{ AOT assemblies");
|
||||||
|
codes.Add("\tpublic static readonly IReadOnlyList<string> PatchedAOTAssemblyList = new List<string>");
|
||||||
|
codes.Add("\t{");
|
||||||
|
List<dnlib.DotNet.ModuleDef> modules = new HashSet<dnlib.DotNet.ModuleDef>(
|
||||||
|
types.Select(t => t.Type.Module).Concat(methods.Select(m => m.Method.Module))).ToList();
|
||||||
|
modules.Sort((a, b) => a.Name.CompareTo(b.Name));
|
||||||
|
foreach (dnlib.DotNet.ModuleDef module in modules)
|
||||||
|
{
|
||||||
|
codes.Add($"\t\t\"{module.Name}\",");
|
||||||
|
}
|
||||||
|
codes.Add("\t};");
|
||||||
|
codes.Add("\t// }}");
|
||||||
|
|
||||||
|
|
||||||
codes.Add("");
|
codes.Add("");
|
||||||
codes.Add("\t// {{ constraint implement type");
|
codes.Add("\t// {{ constraint implement type");
|
||||||
|
|
||||||
codes.Add("\t// }} ");
|
codes.Add("\t// }} ");
|
||||||
|
|
||||||
codes.Add("");
|
codes.Add("");
|
||||||
codes.Add("\t// {{ AOT generic type");
|
codes.Add("\t// {{ AOT generic types");
|
||||||
|
|
||||||
types.Sort((a, b) => a.Type.FullName.CompareTo(b.Type.FullName));
|
List<string> typeNames = types.Select(t => PrettifyTypeSig(t.ToTypeSig().ToString())).ToList();
|
||||||
foreach(var type in types)
|
typeNames.Sort(string.CompareOrdinal);
|
||||||
|
foreach(var typeName in typeNames)
|
||||||
{
|
{
|
||||||
codes.Add($"\t//{type.ToTypeSig()}");
|
codes.Add($"\t// {typeName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
codes.Add("\t// }}");
|
codes.Add("\t// }}");
|
||||||
|
|
@ -39,27 +103,36 @@ namespace HybridCLR.Editor.AOT
|
||||||
codes.Add("");
|
codes.Add("");
|
||||||
codes.Add("\tpublic void RefMethods()");
|
codes.Add("\tpublic void RefMethods()");
|
||||||
codes.Add("\t{");
|
codes.Add("\t{");
|
||||||
methods.Sort((a, b) =>
|
|
||||||
|
List<(string, string, string)> methodTypeAndNames = methods.Select(m =>
|
||||||
|
(PrettifyTypeSig(m.Method.DeclaringType.ToString()), PrettifyMethodSig(m.Method.Name), PrettifyMethodSig(m.ToMethodSpec().ToString())))
|
||||||
|
.ToList();
|
||||||
|
methodTypeAndNames.Sort((a, b) =>
|
||||||
{
|
{
|
||||||
int c = a.Method.DeclaringType.FullName.CompareTo(b.Method.DeclaringType.FullName);
|
int c = String.Compare(a.Item1, b.Item1, StringComparison.Ordinal);
|
||||||
if (c != 0)
|
if (c != 0)
|
||||||
{
|
{
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
c = a.Method.Name.CompareTo(b.Method.Name);
|
|
||||||
return c;
|
c = String.Compare(a.Item2, b.Item2, StringComparison.Ordinal);
|
||||||
});
|
if (c != 0)
|
||||||
foreach(var method in methods)
|
|
||||||
{
|
{
|
||||||
codes.Add($"\t\t// {method.ToMethodSpec()}");
|
return c;
|
||||||
|
}
|
||||||
|
return String.Compare(a.Item3, b.Item3, StringComparison.Ordinal);
|
||||||
|
});
|
||||||
|
foreach(var method in methodTypeAndNames)
|
||||||
|
{
|
||||||
|
codes.Add($"\t\t// {PrettifyMethodSig(method.Item3)}");
|
||||||
}
|
}
|
||||||
codes.Add("\t}");
|
codes.Add("\t}");
|
||||||
|
|
||||||
codes.Add("}");
|
codes.Add("}");
|
||||||
|
|
||||||
|
|
||||||
var utf8WithoutBOM = new System.Text.UTF8Encoding(false);
|
var utf8WithoutBom = new System.Text.UTF8Encoding(false);
|
||||||
File.WriteAllText(outputFile, string.Join("\n", codes), utf8WithoutBOM);
|
File.WriteAllText(outputFile, string.Join("\n", codes), utf8WithoutBom);
|
||||||
Debug.Log($"[GenericReferenceWriter] write {outputFile}");
|
Debug.Log($"[GenericReferenceWriter] write {outputFile}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,258 @@
|
||||||
|
using System;
|
||||||
|
using HybridCLR.Editor.Installer;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
using HybridCLR.Editor.Settings;
|
||||||
|
#if UNITY_2019 && (UNITY_IOS || UNITY_TVOS)
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
using UnityEditor.iOS.Xcode;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
public static class AddLil2cppSourceCodeToXcodeproj2019
|
||||||
|
{
|
||||||
|
[PostProcessBuild]
|
||||||
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
if (!HybridCLRSettings.Instance.enable)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
* 1. 生成lump,并且添加到工程
|
||||||
|
3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp
|
||||||
|
3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include
|
||||||
|
4. 将external目录复制到 Library/external。删除旧目录
|
||||||
|
5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写
|
||||||
|
6. 将 external/zlib下c 文件添加到工程
|
||||||
|
7. 移除libil2cpp.a
|
||||||
|
8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include
|
||||||
|
9. add external/xxHash
|
||||||
|
10. add "#include <stdio.h>" to Classes/Prefix.pch
|
||||||
|
*/
|
||||||
|
|
||||||
|
string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject);
|
||||||
|
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
|
||||||
|
string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp";
|
||||||
|
string lumpDir = $"{pathToBuiltProject}/Libraries/lumps";
|
||||||
|
string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external";
|
||||||
|
string dstExternalDir = $"{pathToBuiltProject}/Libraries/external";
|
||||||
|
//RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir);
|
||||||
|
CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir);
|
||||||
|
CopyExternalToXcodeProj(srcExternalDir, dstExternalDir);
|
||||||
|
var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir);
|
||||||
|
var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir);
|
||||||
|
var cflags = new List<string>()
|
||||||
|
{
|
||||||
|
"-DIL2CPP_MONO_DEBUGGER_DISABLED",
|
||||||
|
};
|
||||||
|
ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags);
|
||||||
|
AddSystemHeaderToPrefixPch(pathToBuiltProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AddSystemHeaderToPrefixPch(string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
// 如果不将 stdio.h 添加到 Prefix.pch, zutil.c会有编译错误
|
||||||
|
string prefixPchFile = $"{pathToBuiltProject}/Classes/Prefix.pch";
|
||||||
|
string fileContent = File.ReadAllText(prefixPchFile, Encoding.UTF8);
|
||||||
|
if (!fileContent.Contains("stdio.h"))
|
||||||
|
{
|
||||||
|
string newFileContent = fileContent + "\n#include <stdio.h>\n";
|
||||||
|
File.WriteAllText(prefixPchFile, newFileContent, Encoding.UTF8);
|
||||||
|
UnityEngine.Debug.Log($"append header to {prefixPchFile}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRelativePathFromProj(string path)
|
||||||
|
{
|
||||||
|
return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List<LumpFile> lumpFiles, List<string> extraFiles, List<string> cflags)
|
||||||
|
{
|
||||||
|
var proj = new PBXProject();
|
||||||
|
proj.ReadFromFile(pbxprojFile);
|
||||||
|
string targetGUID = proj.GetUnityFrameworkTargetGuid();
|
||||||
|
// 移除旧的libil2cpp.a
|
||||||
|
var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a");
|
||||||
|
if (!string.IsNullOrEmpty(libil2cppGUID))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, libil2cppGUID);
|
||||||
|
proj.RemoveFile(libil2cppGUID);
|
||||||
|
File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group);
|
||||||
|
|
||||||
|
foreach (var lumpFile in lumpFiles)
|
||||||
|
{
|
||||||
|
string lumpFileName = Path.GetFileName(lumpFile.lumpFile);
|
||||||
|
string projPathOfFile = $"Classes/Lumps/{lumpFileName}";
|
||||||
|
string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile);
|
||||||
|
string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
|
||||||
|
if (!string.IsNullOrEmpty(lumpGuid))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, lumpGuid);
|
||||||
|
proj.RemoveFile(lumpGuid);
|
||||||
|
}
|
||||||
|
lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source);
|
||||||
|
proj.AddFileToBuild(targetGUID, lumpGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var extraFile in extraFiles)
|
||||||
|
{
|
||||||
|
string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}";
|
||||||
|
string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
|
||||||
|
if (!string.IsNullOrEmpty(extraFileGuid))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, extraFileGuid);
|
||||||
|
proj.RemoveFile(extraFileGuid);
|
||||||
|
//Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}");
|
||||||
|
}
|
||||||
|
var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source);
|
||||||
|
proj.AddFileToBuild(targetGUID, lumpGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var configName in proj.BuildConfigNames())
|
||||||
|
{
|
||||||
|
//Debug.Log($"build config:{bcn}");
|
||||||
|
string configGuid = proj.BuildConfigByName(targetGUID, configName);
|
||||||
|
string headerSearchPaths = "HEADER_SEARCH_PATHS";
|
||||||
|
string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths);
|
||||||
|
//Debug.Log($"config guid:{configGuid} prop:{hspProp}");
|
||||||
|
string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp")
|
||||||
|
.Replace("Libraries/bdwgc", "Libraries/external/bdwgc");
|
||||||
|
|
||||||
|
//if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"))
|
||||||
|
//{
|
||||||
|
// newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include";
|
||||||
|
//}
|
||||||
|
if (!newPro.Contains("Libraries/external/xxHash"))
|
||||||
|
{
|
||||||
|
newPro += " $(SRCROOT)/Libraries/external/xxHash";
|
||||||
|
}
|
||||||
|
newPro += " $(SRCR00T)/Libraries/external/mono";
|
||||||
|
//Debug.Log($"config:{bcn} new prop:{newPro}");
|
||||||
|
proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro);
|
||||||
|
|
||||||
|
string cflagKey = "OTHER_CFLAGS";
|
||||||
|
string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey);
|
||||||
|
foreach (var flag in cflags)
|
||||||
|
{
|
||||||
|
if (!cfProp.Contains(flag))
|
||||||
|
{
|
||||||
|
cfProp += " " + flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG="))
|
||||||
|
{
|
||||||
|
cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1";
|
||||||
|
}
|
||||||
|
proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp);
|
||||||
|
|
||||||
|
}
|
||||||
|
proj.WriteToFile(pbxprojFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir)
|
||||||
|
{
|
||||||
|
BashUtil.RemoveDir(dstLibil2cppDir);
|
||||||
|
BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir)
|
||||||
|
{
|
||||||
|
BashUtil.RemoveDir(dstExternalDir);
|
||||||
|
BashUtil.CopyDir(srcExternalDir, dstExternalDir, true);
|
||||||
|
|
||||||
|
//string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms";
|
||||||
|
//BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS");
|
||||||
|
//BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LumpFile
|
||||||
|
{
|
||||||
|
public List<string> cppFiles = new List<string>();
|
||||||
|
|
||||||
|
public readonly string lumpFile;
|
||||||
|
|
||||||
|
public readonly string il2cppConfigFile;
|
||||||
|
|
||||||
|
public LumpFile(string lumpFile, string il2cppConfigFile)
|
||||||
|
{
|
||||||
|
this.lumpFile = lumpFile;
|
||||||
|
this.il2cppConfigFile = il2cppConfigFile;
|
||||||
|
this.cppFiles.Add(il2cppConfigFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveFile()
|
||||||
|
{
|
||||||
|
var lumpFileContent = new List<string>();
|
||||||
|
foreach (var file in cppFiles)
|
||||||
|
{
|
||||||
|
lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\"");
|
||||||
|
}
|
||||||
|
File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8);
|
||||||
|
Debug.Log($"create lump file:{lumpFile}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<LumpFile> CreateLumps(string libil2cppDir, string outputDir)
|
||||||
|
{
|
||||||
|
BashUtil.RecreateDir(outputDir);
|
||||||
|
|
||||||
|
string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h";
|
||||||
|
var lumpFiles = new List<LumpFile>();
|
||||||
|
int lumpFileIndex = 0;
|
||||||
|
foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir}))
|
||||||
|
{
|
||||||
|
var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile);
|
||||||
|
foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
lumpFile.cppFiles.Add(file);
|
||||||
|
}
|
||||||
|
lumpFile.SaveFile();
|
||||||
|
lumpFiles.Add(lumpFile);
|
||||||
|
++lumpFileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories);
|
||||||
|
if (mmFiles.Length > 0)
|
||||||
|
{
|
||||||
|
var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile);
|
||||||
|
foreach (var file in mmFiles)
|
||||||
|
{
|
||||||
|
lumpFile.cppFiles.Add(file);
|
||||||
|
}
|
||||||
|
lumpFile.SaveFile();
|
||||||
|
lumpFiles.Add(lumpFile);
|
||||||
|
}
|
||||||
|
return lumpFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetExtraSourceFiles(string externalDir, string libil2cppDir)
|
||||||
|
{
|
||||||
|
var files = new List<string>();
|
||||||
|
foreach (string extraDir in new string[]
|
||||||
|
{
|
||||||
|
$"{externalDir}/zlib",
|
||||||
|
$"{externalDir}/xxHash",
|
||||||
|
$"{libil2cppDir}/os/ClassLibraryPAL/brotli",
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(extraDir))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories));
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d2f62ca12f2eb4f2fba8e9cb51279421
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,244 @@
|
||||||
|
using System;
|
||||||
|
using HybridCLR.Editor.Installer;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
using HybridCLR.Editor.Settings;
|
||||||
|
#if (UNITY_2020 || UNITY_2021) && (UNITY_IOS || UNITY_TVOS)
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
using UnityEditor.iOS.Xcode;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
public static class AddLil2cppSourceCodeToXcodeproj2020Or2021
|
||||||
|
{
|
||||||
|
|
||||||
|
[PostProcessBuild]
|
||||||
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
if (!HybridCLRSettings.Instance.enable)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
* 1. 生成lump,并且添加到工程
|
||||||
|
3. 将libil2cpp目录复制到 Library/. 删除旧的. search paths里修改 libil2cpp/include为libil2cpp
|
||||||
|
3. Libraries/bdwgc/include -> Libraries/external/bdwgc/include
|
||||||
|
4. 将external目录复制到 Library/external。删除旧目录
|
||||||
|
5. 将Library/external/baselib/Platforms/OSX改名为 IOS 全大写
|
||||||
|
6. 将 external/zlib下c 文件添加到工程
|
||||||
|
7. 移除libil2cpp.a
|
||||||
|
8. Include path add libil2cpp/os/ClassLibraryPAL/brotli/include
|
||||||
|
9. add external/xxHash
|
||||||
|
*/
|
||||||
|
|
||||||
|
string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject);
|
||||||
|
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
|
||||||
|
string dstLibil2cppDir = $"{pathToBuiltProject}/Libraries/libil2cpp";
|
||||||
|
string lumpDir = $"{pathToBuiltProject}/Libraries/lumps";
|
||||||
|
string srcExternalDir = $"{SettingsUtil.LocalIl2CppDir}/external";
|
||||||
|
string dstExternalDir = $"{pathToBuiltProject}/Libraries/external";
|
||||||
|
//RemoveExternalLibil2cppOption(srcExternalDir, dstExternalDir);
|
||||||
|
CopyLibil2cppToXcodeProj(srcLibil2cppDir, dstLibil2cppDir);
|
||||||
|
CopyExternalToXcodeProj(srcExternalDir, dstExternalDir);
|
||||||
|
var lumpFiles = CreateLumps(dstLibil2cppDir, lumpDir);
|
||||||
|
var extraSources = GetExtraSourceFiles(dstExternalDir, dstLibil2cppDir);
|
||||||
|
var cflags = new List<string>()
|
||||||
|
{
|
||||||
|
"-DIL2CPP_MONO_DEBUGGER_DISABLED",
|
||||||
|
};
|
||||||
|
ModifyPBXProject(pathToBuiltProject, pbxprojFile, lumpFiles, extraSources, cflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetRelativePathFromProj(string path)
|
||||||
|
{
|
||||||
|
return path.Substring(path.IndexOf("Libraries", StringComparison.Ordinal)).Replace('\\', '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ModifyPBXProject(string pathToBuiltProject, string pbxprojFile, List<LumpFile> lumpFiles, List<string> extraFiles, List<string> cflags)
|
||||||
|
{
|
||||||
|
var proj = new PBXProject();
|
||||||
|
proj.ReadFromFile(pbxprojFile);
|
||||||
|
string targetGUID = proj.GetUnityFrameworkTargetGuid();
|
||||||
|
// 移除旧的libil2cpp.a
|
||||||
|
var libil2cppGUID = proj.FindFileGuidByProjectPath("Libraries/libil2cpp.a");
|
||||||
|
if (!string.IsNullOrEmpty(libil2cppGUID))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, libil2cppGUID);
|
||||||
|
proj.RemoveFile(libil2cppGUID);
|
||||||
|
File.Delete(Path.Combine(pathToBuiltProject, "Libraries", "libil2cpp.a"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//var lumpGroupGuid = proj.AddFile("Lumps", $"Classes/Lumps", PBXSourceTree.Group);
|
||||||
|
|
||||||
|
foreach (var lumpFile in lumpFiles)
|
||||||
|
{
|
||||||
|
string lumpFileName = Path.GetFileName(lumpFile.lumpFile);
|
||||||
|
string projPathOfFile = $"Classes/Lumps/{lumpFileName}";
|
||||||
|
string relativePathOfFile = GetRelativePathFromProj(lumpFile.lumpFile);
|
||||||
|
string lumpGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
|
||||||
|
if (!string.IsNullOrEmpty(lumpGuid))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, lumpGuid);
|
||||||
|
proj.RemoveFile(lumpGuid);
|
||||||
|
}
|
||||||
|
lumpGuid = proj.AddFile(relativePathOfFile, projPathOfFile, PBXSourceTree.Source);
|
||||||
|
proj.AddFileToBuild(targetGUID, lumpGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var extraFile in extraFiles)
|
||||||
|
{
|
||||||
|
string projPathOfFile = $"Classes/Extrals/{Path.GetFileName(extraFile)}";
|
||||||
|
string extraFileGuid = proj.FindFileGuidByProjectPath(projPathOfFile);
|
||||||
|
if (!string.IsNullOrEmpty(extraFileGuid))
|
||||||
|
{
|
||||||
|
proj.RemoveFileFromBuild(targetGUID, extraFileGuid);
|
||||||
|
proj.RemoveFile(extraFileGuid);
|
||||||
|
//Debug.LogWarning($"remove exist extra file:{projPathOfFile} guid:{extraFileGuid}");
|
||||||
|
}
|
||||||
|
var lumpGuid = proj.AddFile(GetRelativePathFromProj(extraFile), projPathOfFile, PBXSourceTree.Source);
|
||||||
|
proj.AddFileToBuild(targetGUID, lumpGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(var configName in proj.BuildConfigNames())
|
||||||
|
{
|
||||||
|
//Debug.Log($"build config:{bcn}");
|
||||||
|
string configGuid = proj.BuildConfigByName(targetGUID, configName);
|
||||||
|
string headerSearchPaths = "HEADER_SEARCH_PATHS";
|
||||||
|
string hspProp = proj.GetBuildPropertyForConfig(configGuid, headerSearchPaths);
|
||||||
|
//Debug.Log($"config guid:{configGuid} prop:{hspProp}");
|
||||||
|
string newPro = hspProp.Replace("libil2cpp/include", "libil2cpp")
|
||||||
|
.Replace("Libraries/bdwgc", "Libraries/external/bdwgc");
|
||||||
|
|
||||||
|
if (!newPro.Contains("Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include"))
|
||||||
|
{
|
||||||
|
newPro += " $(SRCROOT)/Libraries/libil2cpp/os/ClassLibraryPAL/brotli/include";
|
||||||
|
}
|
||||||
|
if (!newPro.Contains("Libraries/external/xxHash"))
|
||||||
|
{
|
||||||
|
newPro += " $(SRCROOT)/Libraries/external/xxHash";
|
||||||
|
}
|
||||||
|
newPro += " $(SRCR00T)/Libraries/external/mono";
|
||||||
|
//Debug.Log($"config:{bcn} new prop:{newPro}");
|
||||||
|
proj.SetBuildPropertyForConfig(configGuid, headerSearchPaths, newPro);
|
||||||
|
|
||||||
|
string cflagKey = "OTHER_CFLAGS";
|
||||||
|
string cfProp = proj.GetBuildPropertyForConfig(configGuid, cflagKey);
|
||||||
|
foreach (var flag in cflags)
|
||||||
|
{
|
||||||
|
if (!cfProp.Contains(flag))
|
||||||
|
{
|
||||||
|
cfProp += " " + flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (configName.Contains("Debug") && !cfProp.Contains("-DIL2CPP_DEBUG="))
|
||||||
|
{
|
||||||
|
cfProp += " -DIL2CPP_DEBUG=1 -DDEBUG=1";
|
||||||
|
}
|
||||||
|
proj.SetBuildPropertyForConfig(configGuid, cflagKey, cfProp);
|
||||||
|
|
||||||
|
}
|
||||||
|
proj.WriteToFile(pbxprojFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyLibil2cppToXcodeProj(string srcLibil2cppDir, string dstLibil2cppDir)
|
||||||
|
{
|
||||||
|
BashUtil.RemoveDir(dstLibil2cppDir);
|
||||||
|
BashUtil.CopyDir(srcLibil2cppDir, dstLibil2cppDir, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void CopyExternalToXcodeProj(string srcExternalDir, string dstExternalDir)
|
||||||
|
{
|
||||||
|
BashUtil.RemoveDir(dstExternalDir);
|
||||||
|
BashUtil.CopyDir(srcExternalDir, dstExternalDir, true);
|
||||||
|
|
||||||
|
string baselibPlatfromsDir = $"{dstExternalDir}/baselib/Platforms";
|
||||||
|
BashUtil.RemoveDir($"{baselibPlatfromsDir}/IOS");
|
||||||
|
BashUtil.CopyDir($"{baselibPlatfromsDir}/OSX", $"{baselibPlatfromsDir}/IOS", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
class LumpFile
|
||||||
|
{
|
||||||
|
public List<string> cppFiles = new List<string>();
|
||||||
|
|
||||||
|
public readonly string lumpFile;
|
||||||
|
|
||||||
|
public readonly string il2cppConfigFile;
|
||||||
|
|
||||||
|
public LumpFile(string lumpFile, string il2cppConfigFile)
|
||||||
|
{
|
||||||
|
this.lumpFile = lumpFile;
|
||||||
|
this.il2cppConfigFile = il2cppConfigFile;
|
||||||
|
this.cppFiles.Add(il2cppConfigFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveFile()
|
||||||
|
{
|
||||||
|
var lumpFileContent = new List<string>();
|
||||||
|
foreach (var file in cppFiles)
|
||||||
|
{
|
||||||
|
lumpFileContent.Add($"#include \"{GetRelativePathFromProj(file)}\"");
|
||||||
|
}
|
||||||
|
File.WriteAllLines(lumpFile, lumpFileContent, Encoding.UTF8);
|
||||||
|
Debug.Log($"create lump file:{lumpFile}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<LumpFile> CreateLumps(string libil2cppDir, string outputDir)
|
||||||
|
{
|
||||||
|
BashUtil.RecreateDir(outputDir);
|
||||||
|
|
||||||
|
string il2cppConfigFile = $"{libil2cppDir}/il2cpp-config.h";
|
||||||
|
var lumpFiles = new List<LumpFile>();
|
||||||
|
int lumpFileIndex = 0;
|
||||||
|
foreach (var cppDir in Directory.GetDirectories(libil2cppDir, "*", SearchOption.AllDirectories).Concat(new string[] {libil2cppDir}))
|
||||||
|
{
|
||||||
|
var lumpFile = new LumpFile($"{outputDir}/lump_{Path.GetFileName(cppDir)}_{lumpFileIndex}.cpp", il2cppConfigFile);
|
||||||
|
foreach (var file in Directory.GetFiles(cppDir, "*.cpp", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
lumpFile.cppFiles.Add(file);
|
||||||
|
}
|
||||||
|
lumpFile.SaveFile();
|
||||||
|
lumpFiles.Add(lumpFile);
|
||||||
|
++lumpFileIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mmFiles = Directory.GetFiles(libil2cppDir, "*.mm", SearchOption.AllDirectories);
|
||||||
|
if (mmFiles.Length > 0)
|
||||||
|
{
|
||||||
|
var lumpFile = new LumpFile($"{outputDir}/lump_mm.mm", il2cppConfigFile);
|
||||||
|
foreach (var file in mmFiles)
|
||||||
|
{
|
||||||
|
lumpFile.cppFiles.Add(file);
|
||||||
|
}
|
||||||
|
lumpFile.SaveFile();
|
||||||
|
lumpFiles.Add(lumpFile);
|
||||||
|
}
|
||||||
|
return lumpFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetExtraSourceFiles(string externalDir, string libil2cppDir)
|
||||||
|
{
|
||||||
|
var files = new List<string>();
|
||||||
|
foreach (string extraDir in new string[]
|
||||||
|
{
|
||||||
|
$"{externalDir}/zlib",
|
||||||
|
$"{externalDir}/xxHash",
|
||||||
|
$"{libil2cppDir}/os/ClassLibraryPAL/brotli",
|
||||||
|
})
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(extraDir))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
files.AddRange(Directory.GetFiles(extraDir, "*.c", SearchOption.AllDirectories));
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 61948fcb1bc40ba47b8c10b0ae801ebb
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
using HybridCLR.Editor.Installer;
|
||||||
|
using HybridCLR.Editor.Settings;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#if UNITY_2022 && (UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS)
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer
|
||||||
|
{
|
||||||
|
|
||||||
|
[PostProcessBuild]
|
||||||
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
if (!HybridCLRSettings.Instance.enable)
|
||||||
|
return;
|
||||||
|
string pbxprojFile = BuildProcessorUtil.GetXcodeProjectFile(pathToBuiltProject);
|
||||||
|
RemoveExternalLibil2cppOption(pbxprojFile);
|
||||||
|
CopyLibil2cppToXcodeProj(pathToBuiltProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string TryRemoveDunplicateShellScriptSegment(string pbxprojFile, string pbxprojContent)
|
||||||
|
{
|
||||||
|
// will appear duplicated Shell Script segment when append to existed xcode project.
|
||||||
|
// This is unity bug.
|
||||||
|
// we remove duplicated Shell Script to avoid build error.
|
||||||
|
string copyFileComment = @"/\* CopyFiles \*/,\s+([A-Z0-9]{24}) /\* ShellScript \*/,\s+([A-Z0-9]{24}) /\* ShellScript \*/,";
|
||||||
|
var m = Regex.Match(pbxprojContent, copyFileComment, RegexOptions.Multiline);
|
||||||
|
if (!m.Success)
|
||||||
|
{
|
||||||
|
return pbxprojContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m.Groups[1].Value != m.Groups[2].Value)
|
||||||
|
{
|
||||||
|
throw new BuildFailedException($"find invalid /* ShellScript */ segment");
|
||||||
|
}
|
||||||
|
|
||||||
|
int startIndexOfDupShellScript = m.Groups[2].Index;
|
||||||
|
int endIndexOfDupShellScript = pbxprojContent.IndexOf(",", startIndexOfDupShellScript);
|
||||||
|
|
||||||
|
pbxprojContent = pbxprojContent.Remove(startIndexOfDupShellScript, endIndexOfDupShellScript + 1 - startIndexOfDupShellScript);
|
||||||
|
Debug.LogWarning($"[AddLil2cppSourceCodeToXcodeproj] remove duplicated '/* ShellScript */' from file '{pbxprojFile}'");
|
||||||
|
return pbxprojContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveExternalLibil2cppOption(string pbxprojFile)
|
||||||
|
{
|
||||||
|
string pbxprojContent = File.ReadAllText(pbxprojFile, Encoding.UTF8);
|
||||||
|
string removeBuildOption = @"--external-lib-il2-cpp=\""$PROJECT_DIR/Libraries/libil2cpp.a\""";
|
||||||
|
if (pbxprojContent.Contains(removeBuildOption))
|
||||||
|
{
|
||||||
|
pbxprojContent = pbxprojContent.Replace(removeBuildOption, "");
|
||||||
|
Debug.Log($"[AddLil2cppSourceCodeToXcodeproj] remove il2cpp build option '{removeBuildOption}' from file '{pbxprojFile}'");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"[AddLil2cppSourceCodeToXcodeproj] project.pbxproj remove building option:'{removeBuildOption}' fail. This may occur when 'Append' to existing xcode project in building");
|
||||||
|
}
|
||||||
|
|
||||||
|
pbxprojContent = TryRemoveDunplicateShellScriptSegment(pbxprojFile, pbxprojContent);
|
||||||
|
|
||||||
|
|
||||||
|
File.WriteAllText(pbxprojFile, pbxprojContent, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
|
||||||
|
string destLibil2cppDir = $"{pathToBuiltProject}/Il2CppOutputProject/IL2CPP/libil2cpp";
|
||||||
|
BashUtil.RemoveDir(destLibil2cppDir);
|
||||||
|
BashUtil.CopyDir(srcLibil2cppDir, destLibil2cppDir, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a4ce072f7e4a17248a3d9ebfd011356b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
using HybridCLR.Editor.Installer;
|
||||||
|
using HybridCLR.Editor.Settings;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#if UNITY_2023_1_OR_NEWER && (UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS)
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
public static class AddLil2cppSourceCodeToXcodeproj2022OrNewer
|
||||||
|
{
|
||||||
|
|
||||||
|
[PostProcessBuild]
|
||||||
|
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
if (!HybridCLRSettings.Instance.enable)
|
||||||
|
return;
|
||||||
|
CopyLibil2cppToXcodeProj(pathToBuiltProject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyLibil2cppToXcodeProj(string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
string srcLibil2cppDir = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp";
|
||||||
|
string destLibil2cppDir = $"{pathToBuiltProject}/Il2CppOutputProject/IL2CPP/libil2cpp";
|
||||||
|
BashUtil.RemoveDir(destLibil2cppDir);
|
||||||
|
BashUtil.CopyDir(srcLibil2cppDir, destLibil2cppDir, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2fa46135129b046a28014d58fdfd18ca
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
|
||||||
|
public static class BuildProcessorUtil
|
||||||
|
{
|
||||||
|
|
||||||
|
public static string GetXcodeProjectFile(string pathToBuiltProject)
|
||||||
|
{
|
||||||
|
foreach (string dir in Directory.GetDirectories(pathToBuiltProject, "*.xcodeproj", SearchOption.TopDirectoryOnly))
|
||||||
|
{
|
||||||
|
string pbxprojFile = $"{dir}/project.pbxproj";
|
||||||
|
if (File.Exists(pbxprojFile))
|
||||||
|
{
|
||||||
|
return pbxprojFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new BuildFailedException($"can't find xxxx.xcodeproj/project.pbxproj in {pathToBuiltProject}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c680e56f90f2745298a90803c04f6efc
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,11 +1,16 @@
|
||||||
using System;
|
using HybridCLR.Editor.Settings;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEditor;
|
||||||
using UnityEditor.Build;
|
using UnityEditor.Build;
|
||||||
using UnityEditor.Build.Reporting;
|
using UnityEditor.Build.Reporting;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using static UnityEngine.GraphicsBuffer;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.BuildProcessors
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
{
|
{
|
||||||
|
|
@ -13,17 +18,18 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
{
|
{
|
||||||
public int callbackOrder => 0;
|
public int callbackOrder => 0;
|
||||||
|
|
||||||
|
public static bool DisableMethodBridgeDevelopmentFlagChecking { get; set; }
|
||||||
|
|
||||||
public void OnPreprocessBuild(BuildReport report)
|
public void OnPreprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
HybridCLRSettings globalSettings = SettingsUtil.HybridCLRSettings;
|
HybridCLRSettings globalSettings = SettingsUtil.HybridCLRSettings;
|
||||||
#if !UNITY_2020_1_OR_NEWER || !UNITY_IOS
|
|
||||||
if (!globalSettings.enable || globalSettings.useGlobalIl2cpp)
|
if (!globalSettings.enable || globalSettings.useGlobalIl2cpp)
|
||||||
{
|
{
|
||||||
string oldIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH");
|
string oldIl2cppPath = Environment.GetEnvironmentVariable("UNITY_IL2CPP_PATH");
|
||||||
if (!string.IsNullOrEmpty(oldIl2cppPath))
|
if (!string.IsNullOrEmpty(oldIl2cppPath))
|
||||||
{
|
{
|
||||||
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", "");
|
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", "");
|
||||||
Debug.Log($"[CheckSettings] 清除 UNITY_IL2CPP_PATH, 旧值为:'{oldIl2cppPath}'");
|
Debug.Log($"[CheckSettings] clean process environment variable: UNITY_IL2CPP_PATH, old vlaue:'{oldIl2cppPath}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -32,32 +38,57 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
if (curIl2cppPath != SettingsUtil.LocalIl2CppDir)
|
if (curIl2cppPath != SettingsUtil.LocalIl2CppDir)
|
||||||
{
|
{
|
||||||
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", SettingsUtil.LocalIl2CppDir);
|
Environment.SetEnvironmentVariable("UNITY_IL2CPP_PATH", SettingsUtil.LocalIl2CppDir);
|
||||||
Debug.Log($"[CheckSettings] UNITY_IL2CPP_PATH 当前值为:'{curIl2cppPath}',更新为:'{SettingsUtil.LocalIl2CppDir}'");
|
Debug.Log($"[CheckSettings] UNITY_IL2CPP_PATH old value:'{curIl2cppPath}', new value:'{SettingsUtil.LocalIl2CppDir}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (!globalSettings.enable)
|
if (!globalSettings.enable)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (UnityEditor.PlayerSettings.gcIncremental)
|
BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
|
||||||
|
ScriptingImplementation curScriptingImplementation = PlayerSettings.GetScriptingBackend(buildTargetGroup);
|
||||||
|
ScriptingImplementation targetScriptingImplementation = ScriptingImplementation.IL2CPP;
|
||||||
|
if (curScriptingImplementation != targetScriptingImplementation)
|
||||||
{
|
{
|
||||||
Debug.LogError($"[CheckSettings] HybridCLR不支持增量式GC,已经自动将该选项关闭");
|
Debug.LogError($"[CheckSettings] current ScriptingBackend:{curScriptingImplementation},have been switched to:{targetScriptingImplementation} automatically");
|
||||||
UnityEditor.PlayerSettings.gcIncremental = false;
|
PlayerSettings.SetScriptingBackend(buildTargetGroup, targetScriptingImplementation);
|
||||||
}
|
}
|
||||||
|
|
||||||
var installer = new Installer.InstallerController();
|
var installer = new Installer.InstallerController();
|
||||||
if (!installer.HasInstalledHybridCLR())
|
if (!installer.HasInstalledHybridCLR())
|
||||||
{
|
{
|
||||||
throw new Exception($"你没有初始化HybridCLR,请通过菜单'HybridCLR/Installer'安装");
|
throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (installer.PackageVersion != installer.InstalledLibil2cppVersion)
|
||||||
|
{
|
||||||
|
throw new BuildFailedException($"You must run `HybridCLR/Installer` after upgrading package");
|
||||||
}
|
}
|
||||||
|
|
||||||
HybridCLRSettings gs = SettingsUtil.HybridCLRSettings;
|
HybridCLRSettings gs = SettingsUtil.HybridCLRSettings;
|
||||||
if (((gs.hotUpdateAssemblies?.Length + gs.hotUpdateAssemblyDefinitions?.Length) ?? 0) == 0)
|
if (((gs.hotUpdateAssemblies?.Length + gs.hotUpdateAssemblyDefinitions?.Length) ?? 0) == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[CheckSettings] HybridCLRSettings中未配置任何热更新模块");
|
Debug.LogWarning("[CheckSettings] No hot update modules configured in HybridCLRSettings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!DisableMethodBridgeDevelopmentFlagChecking)
|
||||||
|
{
|
||||||
|
string methodBridgeFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp";
|
||||||
|
var match = Regex.Match(File.ReadAllText(methodBridgeFile), @"// DEVELOPMENT=(\d)");
|
||||||
|
if (match.Success)
|
||||||
|
{
|
||||||
|
int developmentFlagInMethodBridge = int.Parse(match.Groups[1].Value);
|
||||||
|
int developmentFlagInEditorSettings = EditorUserBuildSettings.development ? 1 : 0;
|
||||||
|
if (developmentFlagInMethodBridge != developmentFlagInEditorSettings)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[CheckSettings] MethodBridge.cpp DEVELOPMENT flag:{developmentFlagInMethodBridge} is inconsistent with EditorUserBuildSettings.development:{developmentFlagInEditorSettings}. Please run 'HybridCLR/Generate/All' before building.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("[CheckSettings] MethodBridge.cpp DEVELOPMENT flag not found. Please run 'HybridCLR/Generate/All' before building.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using HybridCLR.Editor.Installer;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -7,13 +8,15 @@ using System.Threading.Tasks;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Build;
|
using UnityEditor.Build;
|
||||||
using UnityEditor.Build.Reporting;
|
using UnityEditor.Build.Reporting;
|
||||||
using UnityEditor.Il2Cpp;
|
|
||||||
using UnityEditor.UnityLinker;
|
using UnityEditor.UnityLinker;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if !UNITY_2021_1_OR_NEWER
|
||||||
|
using UnityEditor.Il2Cpp;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace HybridCLR.Editor.BuildProcessors
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
{
|
{
|
||||||
internal class CopyStrippedAOTAssemblies : IPostprocessBuildWithReport
|
internal class CopyStrippedAOTAssemblies : IPostprocessBuildWithReport, IPreprocessBuildWithReport
|
||||||
#if !UNITY_2021_1_OR_NEWER
|
#if !UNITY_2021_1_OR_NEWER
|
||||||
, IIl2CppProcessor
|
, IIl2CppProcessor
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -25,19 +28,52 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
public static string GetStripAssembliesDir2021(BuildTarget target)
|
public static string GetStripAssembliesDir2021(BuildTarget target)
|
||||||
{
|
{
|
||||||
string projectDir = SettingsUtil.ProjectDir;
|
string projectDir = SettingsUtil.ProjectDir;
|
||||||
#if UNITY_STANDALONE_WIN
|
switch (target)
|
||||||
|
{
|
||||||
|
case BuildTarget.StandaloneWindows:
|
||||||
|
case BuildTarget.StandaloneWindows64:
|
||||||
return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped";
|
return $"{projectDir}/Library/Bee/artifacts/WinPlayerBuildProgram/ManagedStripped";
|
||||||
#elif UNITY_ANDROID
|
case BuildTarget.StandaloneLinux64:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/LinuxPlayerBuildProgram/ManagedStripped";
|
||||||
|
case BuildTarget.WSAPlayer:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/UWPPlayerBuildProgram/ManagedStripped";
|
||||||
|
case BuildTarget.Android:
|
||||||
return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped";
|
return $"{projectDir}/Library/Bee/artifacts/Android/ManagedStripped";
|
||||||
#elif UNITY_IOS
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
return $"{projectDir}/Temp/StagingArea/Data/Managed/tempStrip";
|
case BuildTarget.HMIAndroid:
|
||||||
#elif UNITY_WEBGL
|
return $"{projectDir}/Library/Bee/artifacts/HMIAndroid/ManagedStripped";
|
||||||
return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped";
|
|
||||||
#elif UNITY_EDITOR_OSX
|
|
||||||
return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped";
|
|
||||||
#else
|
|
||||||
throw new NotSupportedException("GetOriginBuildStripAssembliesDir");
|
|
||||||
#endif
|
#endif
|
||||||
|
case BuildTarget.iOS:
|
||||||
|
#if UNITY_TVOS
|
||||||
|
case BuildTarget.tvOS:
|
||||||
|
#endif
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped";
|
||||||
|
#if UNITY_VISIONOS
|
||||||
|
case BuildTarget.VisionOS:
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/VisionOS/ManagedStripped";
|
||||||
|
#else
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/iOS/ManagedStripped";
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
case BuildTarget.WebGL:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/WebGL/ManagedStripped";
|
||||||
|
case BuildTarget.StandaloneOSX:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/MacStandalonePlayerBuildProgram/ManagedStripped";
|
||||||
|
case BuildTarget.PS4:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/PS4PlayerBuildProgram/ManagedStripped";
|
||||||
|
case BuildTarget.PS5:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/PS5PlayerBuildProgram/ManagedStripped";
|
||||||
|
#if UNITY_WEIXINMINIGAME
|
||||||
|
case BuildTarget.WeixinMiniGame:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/WeixinMiniGame/ManagedStripped";
|
||||||
|
#endif
|
||||||
|
#if UNITY_OPENHARMONY
|
||||||
|
case BuildTarget.OpenHarmony:
|
||||||
|
return $"{projectDir}/Library/Bee/artifacts/OpenHarmonyPlayerBuildProgram/ManagedStripped";
|
||||||
|
#endif
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
private string GetStripAssembliesDir2020(BuildTarget target)
|
private string GetStripAssembliesDir2020(BuildTarget target)
|
||||||
|
|
@ -50,8 +86,8 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
|
||||||
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
|
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
|
||||||
{
|
{
|
||||||
// 此回调只在 2020中调用
|
BuildTarget target = report.summary.platform;
|
||||||
CopyStripDlls(GetStripAssembliesDir2020(data.target), data.target);
|
CopyStripDlls(GetStripAssembliesDir2020(target), target);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -78,10 +114,21 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
|
||||||
public void OnPostprocessBuild(BuildReport report)
|
public void OnPostprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
#if UNITY_2021_1_OR_NEWER && !UNITY_IOS
|
#if UNITY_2021_1_OR_NEWER
|
||||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
BuildTarget target = report.summary.platform;
|
||||||
CopyStripDlls(GetStripAssembliesDir2021(target), target);
|
string srcStripDllPath = GetStripAssembliesDir2021(target);
|
||||||
|
if (!string.IsNullOrEmpty(srcStripDllPath) && Directory.Exists(srcStripDllPath))
|
||||||
|
{
|
||||||
|
CopyStripDlls(srcStripDllPath, target);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnPreprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
BuildTarget target = report.summary.platform;
|
||||||
|
var dstPath = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||||
|
BashUtil.RecreateDir(dstPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using HybridCLR.Editor.Meta;
|
using HybridCLR.Editor.Meta;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -25,15 +26,18 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
return assemblies;
|
return assemblies;
|
||||||
}
|
}
|
||||||
List<string> allHotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
List<string> allHotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
||||||
List<string> allHotupdateDllFiles = SettingsUtil.HotUpdateAssemblyFilesExcludePreserved;
|
|
||||||
|
|
||||||
// 检查是否重复填写
|
// 检查是否重复填写
|
||||||
var hotUpdateDllSet = new HashSet<string>();
|
var hotUpdateDllSet = new HashSet<string>();
|
||||||
foreach(var hotUpdateDll in allHotUpdateDllNames)
|
foreach(var hotUpdateDll in allHotUpdateDllNames)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(hotUpdateDll))
|
||||||
|
{
|
||||||
|
throw new BuildFailedException($"hot update assembly name cann't be empty");
|
||||||
|
}
|
||||||
if (!hotUpdateDllSet.Add(hotUpdateDll))
|
if (!hotUpdateDllSet.Add(hotUpdateDll))
|
||||||
{
|
{
|
||||||
throw new Exception($"热更新 assembly:{hotUpdateDll} 在列表中重复,请除去重复条目");
|
throw new BuildFailedException($"hot update assembly:{hotUpdateDll} is duplicated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,16 +45,24 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
// 检查是否填写了正确的dll名称
|
// 检查是否填写了正确的dll名称
|
||||||
foreach (var hotUpdateDllName in allHotUpdateDllNames)
|
foreach (var hotUpdateDllName in allHotUpdateDllNames)
|
||||||
{
|
{
|
||||||
string hotUpdateDllFile = hotUpdateDllName + ".dll";
|
if (assemblies.Select(Path.GetFileNameWithoutExtension).All(ass => ass != hotUpdateDllName)
|
||||||
if (assemblies.All(ass => !ass.EndsWith(hotUpdateDllFile)) && string.IsNullOrEmpty(assResolver.ResolveAssembly(hotUpdateDllName, false)))
|
&& string.IsNullOrEmpty(assResolver.ResolveAssembly(hotUpdateDllName, false)))
|
||||||
{
|
{
|
||||||
throw new Exception($"热更新 assembly:{hotUpdateDllFile} 不存在,请检查拼写错误");
|
throw new BuildFailedException($"hot update assembly:{hotUpdateDllName} doesn't exist");
|
||||||
}
|
}
|
||||||
Debug.Log($"[FilterHotFixAssemblies] 过滤热更新assembly:{hotUpdateDllFile}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将热更dll从打包列表中移除
|
// 将热更dll从打包列表中移除
|
||||||
return assemblies.Where(ass => allHotupdateDllFiles.All(dll => !ass.EndsWith(dll, StringComparison.OrdinalIgnoreCase))).ToArray();
|
return assemblies.Where(ass =>
|
||||||
|
{
|
||||||
|
string assName = Path.GetFileNameWithoutExtension(ass);
|
||||||
|
bool reserved = allHotUpdateDllNames.All(dll => !assName.Equals(dll, StringComparison.Ordinal));
|
||||||
|
if (!reserved)
|
||||||
|
{
|
||||||
|
Debug.Log($"[FilterHotFixAssemblies] filter assembly:{assName}");
|
||||||
|
}
|
||||||
|
return reserved;
|
||||||
|
}).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
using System;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
|
||||||
|
public class MsvcStdextWorkaround : IPreprocessBuildWithReport
|
||||||
|
{
|
||||||
|
const string kWorkaroundFlag = "/D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS";
|
||||||
|
|
||||||
|
public int callbackOrder => 0;
|
||||||
|
|
||||||
|
public void OnPreprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
var clEnv = Environment.GetEnvironmentVariable("_CL_");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(clEnv))
|
||||||
|
{
|
||||||
|
Environment.SetEnvironmentVariable("_CL_", kWorkaroundFlag);
|
||||||
|
}
|
||||||
|
else if (!clEnv.Contains(kWorkaroundFlag))
|
||||||
|
{
|
||||||
|
clEnv += " " + kWorkaroundFlag;
|
||||||
|
Environment.SetEnvironmentVariable("_CL_", clEnv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UNITY_EDITOR
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8bff6cadf0b8db54b87ba51b24d080f6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -9,21 +9,30 @@ using UnityEditor;
|
||||||
using UnityEditor.Android;
|
using UnityEditor.Android;
|
||||||
using UnityEditor.Build;
|
using UnityEditor.Build;
|
||||||
using UnityEditor.Build.Reporting;
|
using UnityEditor.Build.Reporting;
|
||||||
using UnityEditor.Il2Cpp;
|
|
||||||
using UnityEditor.UnityLinker;
|
using UnityEditor.UnityLinker;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityFS;
|
using UnityFS;
|
||||||
|
#if !UNITY_2023_1_OR_NEWER
|
||||||
|
using UnityEditor.Il2Cpp;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace HybridCLR.Editor.BuildProcessors
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
{
|
{
|
||||||
public class PatchScriptingAssemblyList :
|
public class PatchScriptingAssemblyList :
|
||||||
#if UNITY_ANDROID
|
#if UNITY_ANDROID
|
||||||
IPostGenerateGradleAndroidProject,
|
IPostGenerateGradleAndroidProject,
|
||||||
|
#elif UNITY_OPENHARMONY
|
||||||
|
UnityEditor.OpenHarmony.IPostGenerateOpenHarmonyProject,
|
||||||
#endif
|
#endif
|
||||||
IPostprocessBuildWithReport
|
IPostprocessBuildWithReport
|
||||||
#if !UNITY_2021_1_OR_NEWER && UNITY_WEBGL
|
#if !UNITY_2021_1_OR_NEWER && UNITY_WEBGL
|
||||||
, IIl2CppProcessor
|
, IIl2CppProcessor
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if UNITY_PS5
|
||||||
|
, IUnityLinkerProcessor
|
||||||
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
public int callbackOrder => 0;
|
public int callbackOrder => 0;
|
||||||
|
|
||||||
|
|
@ -42,17 +51,37 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_OPENHARMONY
|
||||||
|
|
||||||
|
public void OnPostGenerateOpenHarmonyProject(string path)
|
||||||
|
{
|
||||||
|
OnPostGenerateGradleAndroidProject(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
public void OnPostprocessBuild(BuildReport report)
|
public void OnPostprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
// 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过,
|
// 如果target为Android,由于已经在OnPostGenerateGradelAndroidProject中处理过,
|
||||||
// 这里不再重复处理
|
// 这里不再重复处理
|
||||||
#if !UNITY_ANDROID && !UNITY_WEBGL
|
#if !UNITY_ANDROID && !UNITY_WEBGL && !UNITY_OPENHARMONY
|
||||||
|
|
||||||
PathScriptingAssembilesFile(report.summary.outputPath);
|
PathScriptingAssembilesFile(report.summary.outputPath);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PathScriptingAssembilesFile(string path)
|
#if UNITY_PS5
|
||||||
|
/// <summary>
|
||||||
|
/// 打包模式如果是 Package 需要在这个阶段提前处理 .json , PC Hosted 和 GP5 模式不受影响
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public string GenerateAdditionalLinkXmlFile(UnityEditor.Build.Reporting.BuildReport report, UnityEditor.UnityLinker.UnityLinkerBuildPipelineData data)
|
||||||
|
{
|
||||||
|
string path = $"{SettingsUtil.ProjectDir}/Library/PlayerDataCache/PS5/Data";
|
||||||
|
PathScriptingAssembilesFile(path);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
public void PathScriptingAssembilesFile(string path)
|
||||||
{
|
{
|
||||||
if (!SettingsUtil.Enable)
|
if (!SettingsUtil.Enable)
|
||||||
{
|
{
|
||||||
|
|
@ -84,7 +113,7 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
|
||||||
if (jsonFiles.Length == 0)
|
if (jsonFiles.Length == 0)
|
||||||
{
|
{
|
||||||
//Debug.LogError($"can not find file {SettingsUtil.ScriptingAssembliesJsonFile}");
|
Debug.LogWarning($"can not find file {SettingsUtil.ScriptingAssembliesJsonFile}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,9 +125,11 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
patcher.Save(file);
|
patcher.Save(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddHotFixAssembliesToBinFile(string path)
|
private void AddHotFixAssembliesToBinFile(string path)
|
||||||
{
|
{
|
||||||
|
#if UNITY_STANDALONE_OSX
|
||||||
|
path = Path.GetDirectoryName(path);
|
||||||
|
#endif
|
||||||
if (AddHotFixAssembliesToGlobalgamemanagers(path))
|
if (AddHotFixAssembliesToGlobalgamemanagers(path))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -148,7 +179,7 @@ namespace HybridCLR.Editor.BuildProcessors
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_WEBGL
|
#if UNITY_WEBGL && !UNITY_2022_3_OR_NEWER
|
||||||
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
|
public void OnBeforeConvertRun(BuildReport report, Il2CppBuildPipelineData data)
|
||||||
{
|
{
|
||||||
PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Temp/StagingArea/Data");
|
PathScriptingAssembilesFile($"{SettingsUtil.ProjectDir}/Temp/StagingArea/Data");
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace HybridCLR.Editor.BuildProcessors
|
||||||
|
{
|
||||||
|
public class ScriptingAssembliesJsonPatcher
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
private class ScriptingAssemblies
|
||||||
|
{
|
||||||
|
public List<string> names;
|
||||||
|
public List<int> types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _file;
|
||||||
|
ScriptingAssemblies _scriptingAssemblies;
|
||||||
|
|
||||||
|
public void Load(string file)
|
||||||
|
{
|
||||||
|
_file = file;
|
||||||
|
string content = File.ReadAllText(file);
|
||||||
|
_scriptingAssemblies = JsonUtility.FromJson<ScriptingAssemblies>(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddScriptingAssemblies(List<string> assemblies)
|
||||||
|
{
|
||||||
|
foreach (string name in assemblies)
|
||||||
|
{
|
||||||
|
if (!_scriptingAssemblies.names.Contains(name))
|
||||||
|
{
|
||||||
|
_scriptingAssemblies.names.Add(name);
|
||||||
|
_scriptingAssemblies.types.Add(16); // user dll type
|
||||||
|
Debug.Log($"[PatchScriptAssembliesJson] add hotfix assembly:{name} to {_file}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(string jsonFile)
|
||||||
|
{
|
||||||
|
string content = JsonUtility.ToJson(_scriptingAssemblies);
|
||||||
|
|
||||||
|
File.WriteAllText(jsonFile, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4455f7304f8678f408dd6cf21734f55e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using HybridCLR.Editor.Meta;
|
using HybridCLR.Editor.Meta;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -10,6 +11,7 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
|
using Analyzer = HybridCLR.Editor.AOT.Analyzer;
|
||||||
public static class AOTReferenceGeneratorCommand
|
public static class AOTReferenceGeneratorCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -21,13 +23,16 @@ namespace HybridCLR.Editor.Commands
|
||||||
GenerateAOTGenericReference(target);
|
GenerateAOTGenericReference(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算热更代码中的泛型引用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
public static void GenerateAOTGenericReference(BuildTarget target)
|
public static void GenerateAOTGenericReference(BuildTarget target)
|
||||||
{
|
{
|
||||||
var gs = SettingsUtil.HybridCLRSettings;
|
var gs = SettingsUtil.HybridCLRSettings;
|
||||||
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
||||||
|
|
||||||
using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames))
|
AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames);
|
||||||
{
|
|
||||||
var analyzer = new Analyzer(new Analyzer.Options
|
var analyzer = new Analyzer(new Analyzer.Options
|
||||||
{
|
{
|
||||||
MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration),
|
MaxIterationCount = Math.Min(20, gs.maxGenericReferenceIteration),
|
||||||
|
|
@ -40,6 +45,88 @@ namespace HybridCLR.Editor.Commands
|
||||||
writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
|
writer.Write(analyzer.AotGenericTypes.ToList(), analyzer.AotGenericMethods.ToList(), $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//[MenuItem("HybridCLR/Generate/AOTGenericReference2", priority = 103)]
|
||||||
|
//public static void GeneratedAOTGenericReferenceExcludeExists()
|
||||||
|
//{
|
||||||
|
// GeneratedAOTGenericReferenceExcludeExists(EditorUserBuildSettings.activeBuildTarget);
|
||||||
|
//}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算热更新代码中的泛型引用,但排除AOT已经存在的泛型引用
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
///
|
||||||
|
public static void GeneratedAOTGenericReferenceExcludeExistsAOTClassAndMethods(BuildTarget target)
|
||||||
|
{
|
||||||
|
|
||||||
|
var gs = SettingsUtil.HybridCLRSettings;
|
||||||
|
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
||||||
|
|
||||||
|
AssemblyReferenceDeepCollector hotUpdateCollector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames);
|
||||||
|
var hotUpdateAnalyzer = new Analyzer(new Analyzer.Options
|
||||||
|
{
|
||||||
|
MaxIterationCount = Math.Min(10, gs.maxGenericReferenceIteration),
|
||||||
|
Collector = hotUpdateCollector,
|
||||||
|
});
|
||||||
|
|
||||||
|
hotUpdateAnalyzer.Run();
|
||||||
|
|
||||||
|
|
||||||
|
string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||||
|
List<string> aotAssemblyNames = Directory.Exists(aotDllDir) ?
|
||||||
|
Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList()
|
||||||
|
: new List<string>();
|
||||||
|
if (aotAssemblyNames.Count == 0)
|
||||||
|
{
|
||||||
|
throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/AOTGenericReference`");
|
||||||
|
}
|
||||||
|
AssemblyReferenceDeepCollector aotCollector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames);
|
||||||
|
var aotAnalyzer = new Analyzer(new Analyzer.Options
|
||||||
|
{
|
||||||
|
MaxIterationCount = Math.Min(10, gs.maxGenericReferenceIteration),
|
||||||
|
Collector = aotCollector,
|
||||||
|
ComputeAotAssembly = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
aotAnalyzer.Run();
|
||||||
|
|
||||||
|
var (resultTypes, resultMethods) = ExcludeExistAOTGenericTypeAndMethodss(hotUpdateAnalyzer.AotGenericTypes.ToList(), hotUpdateAnalyzer.AotGenericMethods.ToList(), aotAnalyzer.AotGenericTypes.ToList(), aotAnalyzer.AotGenericMethods.ToList());
|
||||||
|
var writer = new GenericReferenceWriter();
|
||||||
|
writer.Write(resultTypes, resultMethods, $"{Application.dataPath}/{gs.outputAOTGenericReferenceFile}");
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static (List<GenericClass>, List<GenericMethod>) ExcludeExistAOTGenericTypeAndMethodss(List<GenericClass> hotUpdateTypes, List<GenericMethod> hotUpdateMethods, List<GenericClass> aotTypes, List<GenericMethod> aotMethods)
|
||||||
|
{
|
||||||
|
var types = new List<GenericClass>();
|
||||||
|
|
||||||
|
var typeSig2Type = hotUpdateTypes.ToDictionary(t => t.Type.DefinitionAssembly.Name + ":" + t.ToTypeSig(), t => t);
|
||||||
|
foreach (var t in aotTypes)
|
||||||
|
{
|
||||||
|
string key = t.Type.DefinitionAssembly.Name + ":" + t.ToTypeSig();
|
||||||
|
if (typeSig2Type.TryGetValue(key, out var removedType))
|
||||||
|
{
|
||||||
|
typeSig2Type.Remove(key);
|
||||||
|
Debug.Log($"remove AOT type:{removedType.ToTypeSig()} ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var methodSig2Method = hotUpdateMethods.ToDictionary(m => m.Method.DeclaringType.DefinitionAssembly.Name + ":" + m.ToMethodSpec().ToString(), m => m);
|
||||||
|
foreach (var m in aotMethods)
|
||||||
|
{
|
||||||
|
string key = m.Method.DeclaringType.DefinitionAssembly.Name + ":" + m.ToMethodSpec().ToString();
|
||||||
|
if (methodSig2Method.TryGetValue(key, out var removedMethod))
|
||||||
|
{
|
||||||
|
methodSig2Method.Remove(key);
|
||||||
|
Debug.Log($"remove AOT method:{removedMethod.ToMethodSpec()} ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (typeSig2Type.Values.ToList(), methodSig2Method.Values.ToList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,31 +12,48 @@ namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
public class CompileDllCommand
|
public class CompileDllCommand
|
||||||
{
|
{
|
||||||
public static void CompileDll(string buildDir, BuildTarget target)
|
public static void CompileDll(string buildDir, BuildTarget target, bool developmentBuild)
|
||||||
{
|
{
|
||||||
var group = BuildPipeline.GetBuildTargetGroup(target);
|
var group = BuildPipeline.GetBuildTargetGroup(target);
|
||||||
|
|
||||||
ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
|
ScriptCompilationSettings scriptCompilationSettings = new ScriptCompilationSettings();
|
||||||
scriptCompilationSettings.group = group;
|
scriptCompilationSettings.group = group;
|
||||||
scriptCompilationSettings.target = target;
|
scriptCompilationSettings.target = target;
|
||||||
|
scriptCompilationSettings.options = developmentBuild ? ScriptCompilationOptions.DevelopmentBuild : ScriptCompilationOptions.None;
|
||||||
Directory.CreateDirectory(buildDir);
|
Directory.CreateDirectory(buildDir);
|
||||||
ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
|
ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
|
||||||
foreach (var ass in scriptCompilationResult.assemblies)
|
#if UNITY_2022
|
||||||
{
|
UnityEditor.EditorUtility.ClearProgressBar();
|
||||||
//Debug.LogFormat("compile assemblies:{1}/{0}", ass, buildDir);
|
#endif
|
||||||
}
|
Debug.Log($"compile finish!!! buildDir:{buildDir} target:{target} development:{developmentBuild}");
|
||||||
Debug.Log("compile finish!!!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompileDll(BuildTarget target)
|
public static void CompileDll(BuildTarget target)
|
||||||
{
|
{
|
||||||
CompileDll(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), target);
|
CompileDll(target, EditorUserBuildSettings.development);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CompileDll(BuildTarget target, bool developmentBuild)
|
||||||
|
{
|
||||||
|
CompileDll(SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target), target, developmentBuild);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget", priority = 100)]
|
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget", priority = 100)]
|
||||||
public static void CompileDllActiveBuildTarget()
|
public static void CompileDllActiveBuildTarget()
|
||||||
{
|
{
|
||||||
CompileDll(EditorUserBuildSettings.activeBuildTarget);
|
CompileDll(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.development);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Release", priority = 102)]
|
||||||
|
public static void CompileDllActiveBuildTargetRelease()
|
||||||
|
{
|
||||||
|
CompileDll(EditorUserBuildSettings.activeBuildTarget, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("HybridCLR/CompileDll/ActiveBuildTarget_Development", priority = 104)]
|
||||||
|
public static void CompileDllActiveBuildTargetDevelopment()
|
||||||
|
{
|
||||||
|
CompileDll(EditorUserBuildSettings.activeBuildTarget, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("HybridCLR/CompileDll/Win32", priority = 200)]
|
[MenuItem("HybridCLR/CompileDll/Win32", priority = 200)]
|
||||||
|
|
@ -51,16 +68,34 @@ namespace HybridCLR.Editor.Commands
|
||||||
CompileDll(BuildTarget.StandaloneWindows64);
|
CompileDll(BuildTarget.StandaloneWindows64);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("HybridCLR/CompileDll/Android", priority = 202)]
|
[MenuItem("HybridCLR/CompileDll/MacOS", priority = 202)]
|
||||||
|
public static void CompileDllMacOS()
|
||||||
|
{
|
||||||
|
CompileDll(BuildTarget.StandaloneOSX);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("HybridCLR/CompileDll/Linux", priority = 203)]
|
||||||
|
public static void CompileDllLinux()
|
||||||
|
{
|
||||||
|
CompileDll(BuildTarget.StandaloneLinux64);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem("HybridCLR/CompileDll/Android", priority = 210)]
|
||||||
public static void CompileDllAndroid()
|
public static void CompileDllAndroid()
|
||||||
{
|
{
|
||||||
CompileDll(BuildTarget.Android);
|
CompileDll(BuildTarget.Android);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("HybridCLR/CompileDll/IOS", priority = 203)]
|
[MenuItem("HybridCLR/CompileDll/IOS", priority = 220)]
|
||||||
public static void CompileDllIOS()
|
public static void CompileDllIOS()
|
||||||
{
|
{
|
||||||
CompileDll(BuildTarget.iOS);
|
CompileDll(BuildTarget.iOS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MenuItem("HybridCLR/CompileDll/WebGL", priority = 230)]
|
||||||
|
public static void CompileDllWebGL()
|
||||||
|
{
|
||||||
|
CompileDll(BuildTarget.WebGL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using HybridCLR.Editor.Link;
|
using HybridCLR.Editor.Link;
|
||||||
|
using HybridCLR.Editor.Settings;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
@ -19,8 +20,10 @@ namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
UnityVersion = Application.unityVersion,
|
UnityVersion = Application.unityVersion,
|
||||||
HotUpdateAssemblies = SettingsUtil.HotUpdateAssemblyNamesIncludePreserved,
|
HotUpdateAssemblies = SettingsUtil.HotUpdateAssemblyNamesIncludePreserved,
|
||||||
OutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/il2cpp-config.h",
|
UnityVersionTemplateFile = $"{SettingsUtil.TemplatePathInPackage}/UnityVersion.h.tpl",
|
||||||
OutputFile2 = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/Il2CppCompatibleDef.cpp",
|
UnityVersionOutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/UnityVersion.h",
|
||||||
|
AssemblyManifestTemplateFile = $"{SettingsUtil.TemplatePathInPackage}/AssemblyManifest.cpp.tpl",
|
||||||
|
AssemblyManifestOutputFile = $"{SettingsUtil.LocalIl2CppDir}/libil2cpp/hybridclr/generated/AssemblyManifest.cpp",
|
||||||
};
|
};
|
||||||
|
|
||||||
var g = new Il2CppDef.Il2CppDefGenerator(options);
|
var g = new Il2CppDef.Il2CppDefGenerator(options);
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
using HybridCLR.Editor.Installer;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
|
||||||
{
|
|
||||||
public static class InstallerCommand
|
|
||||||
{
|
|
||||||
|
|
||||||
[MenuItem("HybridCLR/Installer...", false, 0)]
|
|
||||||
private static void Open()
|
|
||||||
{
|
|
||||||
InstallerWindow window = EditorWindow.GetWindow<InstallerWindow>("HybridCLR Installer", true);
|
|
||||||
window.minSize = new Vector2(800f, 500f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: b91d62dfcf14d1241b7654d79d5b98a0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -8,6 +8,7 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
|
using Analyzer = HybridCLR.Editor.Link.Analyzer;
|
||||||
|
|
||||||
public static class LinkGeneratorCommand
|
public static class LinkGeneratorCommand
|
||||||
{
|
{
|
||||||
|
|
@ -26,7 +27,7 @@ namespace HybridCLR.Editor.Commands
|
||||||
|
|
||||||
List<string> hotfixAssemblies = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
List<string> hotfixAssemblies = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
||||||
|
|
||||||
var analyzer = new Analyzer(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotfixAssemblies), HybridCLRSettings.Instance.collectAssetReferenceTypes);
|
var analyzer = new Analyzer(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotfixAssemblies));
|
||||||
var refTypes = analyzer.CollectRefs(hotfixAssemblies);
|
var refTypes = analyzer.CollectRefs(hotfixAssemblies);
|
||||||
|
|
||||||
Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssemblies.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}");
|
Debug.Log($"[LinkGeneratorCommand] hotfix assembly count:{hotfixAssemblies.Count}, ref type count:{refTypes.Count} output:{Application.dataPath}/{ls.outputLinkFile}");
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,12 @@ using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
|
using Analyzer = HybridCLR.Editor.MethodBridge.Analyzer;
|
||||||
public class MethodBridgeGeneratorCommand
|
public class MethodBridgeGeneratorCommand
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -28,55 +30,67 @@ namespace HybridCLR.Editor.Commands
|
||||||
Directory.Delete(il2cppBuildCachePath, true);
|
Directory.Delete(il2cppBuildCachePath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GenerateMethodBridgeCppFile(Analyzer analyzer, PlatformABI platform, string templateCode, string outputFile)
|
private static void GenerateMethodBridgeCppFile(IReadOnlyCollection<GenericMethod> genericMethods, List<RawMonoPInvokeCallbackMethodInfo> reversePInvokeMethods, IReadOnlyCollection<CallNativeMethodSignatureInfo> calliMethodSignatures, string tempFile, string outputFile)
|
||||||
{
|
{
|
||||||
|
string templateCode = File.ReadAllText(tempFile, Encoding.UTF8);
|
||||||
var g = new Generator(new Generator.Options()
|
var g = new Generator(new Generator.Options()
|
||||||
{
|
{
|
||||||
PlatformABI = platform,
|
|
||||||
TemplateCode = templateCode,
|
TemplateCode = templateCode,
|
||||||
OutputFile = outputFile,
|
OutputFile = outputFile,
|
||||||
GenericMethods = analyzer.GenericMethods,
|
GenericMethods = genericMethods,
|
||||||
NotGenericMethods = analyzer.NotGenericMethods,
|
ReversePInvokeMethods = reversePInvokeMethods,
|
||||||
|
CalliMethodSignatures = calliMethodSignatures,
|
||||||
|
Development = EditorUserBuildSettings.development,
|
||||||
});
|
});
|
||||||
|
|
||||||
g.PrepareMethods();
|
|
||||||
g.Generate();
|
g.Generate();
|
||||||
Debug.LogFormat("== output:{0} ==", outputFile);
|
Debug.LogFormat("[MethodBridgeGeneratorCommand] output:{0}", outputFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("HybridCLR/Generate/MethodBridge", priority = 101)]
|
[MenuItem("HybridCLR/Generate/MethodBridgeAndReversePInvokeWrapper", priority = 101)]
|
||||||
public static void CompileAndGenerateMethodBridge()
|
public static void GenerateMethodBridgeAndReversePInvokeWrapper()
|
||||||
{
|
{
|
||||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
||||||
CompileDllCommand.CompileDll(target);
|
GenerateMethodBridgeAndReversePInvokeWrapper(target);
|
||||||
GenerateMethodBridge(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GenerateMethodBridge(BuildTarget target)
|
public static void GenerateMethodBridgeAndReversePInvokeWrapper(BuildTarget target)
|
||||||
{
|
{
|
||||||
List<string> hotUpdateDllNames = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
string aotDllDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||||
using (AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDllNames), hotUpdateDllNames))
|
List<string> aotAssemblyNames = Directory.Exists(aotDllDir) ?
|
||||||
|
Directory.GetFiles(aotDllDir, "*.dll", SearchOption.TopDirectoryOnly).Select(Path.GetFileNameWithoutExtension).ToList()
|
||||||
|
: new List<string>();
|
||||||
|
if (aotAssemblyNames.Count == 0)
|
||||||
{
|
{
|
||||||
var analyzer = new Analyzer(new Analyzer.Options
|
throw new Exception($"no aot assembly found. please run `HybridCLR/Generate/All` or `HybridCLR/Generate/AotDlls` to generate aot dlls before runing `HybridCLR/Generate/MethodBridge`");
|
||||||
|
}
|
||||||
|
AssemblyReferenceDeepCollector collector = new AssemblyReferenceDeepCollector(MetaUtil.CreateAOTAssemblyResolver(target), aotAssemblyNames);
|
||||||
|
|
||||||
|
var methodBridgeAnalyzer = new Analyzer(new Analyzer.Options
|
||||||
{
|
{
|
||||||
MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration),
|
MaxIterationCount = Math.Min(20, SettingsUtil.HybridCLRSettings.maxMethodBridgeGenericIteration),
|
||||||
Collector = collector,
|
Collector = collector,
|
||||||
});
|
});
|
||||||
|
|
||||||
analyzer.Run();
|
methodBridgeAnalyzer.Run();
|
||||||
|
|
||||||
var tasks = new List<Task>();
|
List<string> hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
||||||
string templateCode = File.ReadAllText($"{SettingsUtil.TemplatePathInPackage}/MethodBridgeStub.cpp");
|
var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls));
|
||||||
foreach (PlatformABI platform in Enum.GetValues(typeof(PlatformABI)))
|
|
||||||
{
|
var reversePInvokeAnalyzer = new MonoPInvokeCallbackAnalyzer(cache, hotUpdateDlls);
|
||||||
string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge_{platform}.cpp";
|
reversePInvokeAnalyzer.Run();
|
||||||
tasks.Add(Task.Run(() =>
|
|
||||||
{
|
var calliAnalyzer = new CalliAnalyzer(cache, hotUpdateDlls);
|
||||||
GenerateMethodBridgeCppFile(analyzer, platform, templateCode, outputFile);
|
calliAnalyzer.Run();
|
||||||
}));
|
var pinvokeAnalyzer = new PInvokeAnalyzer(cache, hotUpdateDlls);
|
||||||
}
|
pinvokeAnalyzer.Run();
|
||||||
Task.WaitAll(tasks.ToArray());
|
var callPInvokeMethodSignatures = pinvokeAnalyzer.PInvokeMethodSignatures;
|
||||||
}
|
|
||||||
|
string templateFile = $"{SettingsUtil.TemplatePathInPackage}/MethodBridge.cpp.tpl";
|
||||||
|
string outputFile = $"{SettingsUtil.GeneratedCppDir}/MethodBridge.cpp";
|
||||||
|
|
||||||
|
var callNativeMethodSignatures = calliAnalyzer.CalliMethodSignatures.Concat(pinvokeAnalyzer.PInvokeMethodSignatures).ToList();
|
||||||
|
GenerateMethodBridgeCppFile(methodBridgeAnalyzer.GenericMethods, reversePInvokeAnalyzer.ReversePInvokeMethods, callNativeMethodSignatures, templateFile, outputFile);
|
||||||
|
|
||||||
CleanIl2CppBuildCache();
|
CleanIl2CppBuildCache();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
|
|
@ -15,19 +16,23 @@ namespace HybridCLR.Editor.Commands
|
||||||
[MenuItem("HybridCLR/Generate/All", priority = 200)]
|
[MenuItem("HybridCLR/Generate/All", priority = 200)]
|
||||||
public static void GenerateAll()
|
public static void GenerateAll()
|
||||||
{
|
{
|
||||||
|
var installer = new Installer.InstallerController();
|
||||||
|
if (!installer.HasInstalledHybridCLR())
|
||||||
|
{
|
||||||
|
throw new BuildFailedException($"You have not initialized HybridCLR, please install it via menu 'HybridCLR/Installer'");
|
||||||
|
}
|
||||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
||||||
CompileDllCommand.CompileDll(target);
|
CompileDllCommand.CompileDll(target, EditorUserBuildSettings.development);
|
||||||
Il2CppDefGeneratorCommand.GenerateIl2CppDef();
|
Il2CppDefGeneratorCommand.GenerateIl2CppDef();
|
||||||
|
|
||||||
// 这几个生成依赖HotUpdateDlls
|
// 这几个生成依赖HotUpdateDlls
|
||||||
LinkGeneratorCommand.GenerateLinkXml(target);
|
LinkGeneratorCommand.GenerateLinkXml(target);
|
||||||
|
|
||||||
// 生成裁剪后的aot dll
|
// 生成裁剪后的aot dll
|
||||||
StripAOTDllCommand.GenerateStripedAOTDlls(target, EditorUserBuildSettings.selectedBuildTargetGroup);
|
StripAOTDllCommand.GenerateStripedAOTDlls(target);
|
||||||
|
|
||||||
// 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll
|
// 桥接函数生成依赖于AOT dll,必须保证已经build过,生成AOT dll
|
||||||
MethodBridgeGeneratorCommand.GenerateMethodBridge(target);
|
MethodBridgeGeneratorCommand.GenerateMethodBridgeAndReversePInvokeWrapper(target);
|
||||||
ReversePInvokeWrapperGeneratorCommand.GenerateReversePInvokeWrapper(target);
|
|
||||||
AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target);
|
AOTReferenceGeneratorCommand.GenerateAOTGenericReference(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
using HybridCLR.Editor.ABI;
|
|
||||||
using HybridCLR.Editor.Link;
|
|
||||||
using HybridCLR.Editor.Meta;
|
|
||||||
using HybridCLR.Editor.ReversePInvokeWrap;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
|
||||||
{
|
|
||||||
|
|
||||||
public static class ReversePInvokeWrapperGeneratorCommand
|
|
||||||
{
|
|
||||||
|
|
||||||
[MenuItem("HybridCLR/Generate/ReversePInvokeWrapper", priority = 103)]
|
|
||||||
|
|
||||||
public static void CompileAndGenerateReversePInvokeWrapper()
|
|
||||||
{
|
|
||||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
|
||||||
CompileDllCommand.CompileDll(target);
|
|
||||||
GenerateReversePInvokeWrapper(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void GenerateReversePInvokeWrapper(BuildTarget target)
|
|
||||||
{
|
|
||||||
List<string> hotUpdateDlls = SettingsUtil.HotUpdateAssemblyNamesExcludePreserved;
|
|
||||||
using (var cache = new AssemblyCache(MetaUtil.CreateHotUpdateAndAOTAssemblyResolver(target, hotUpdateDlls)))
|
|
||||||
{
|
|
||||||
var analyzer = new ReversePInvokeWrap.Analyzer(cache, hotUpdateDlls);
|
|
||||||
analyzer.Run();
|
|
||||||
|
|
||||||
|
|
||||||
string templateCode = File.ReadAllText($"{SettingsUtil.TemplatePathInPackage}/ReversePInvokeMethodStub.cpp");
|
|
||||||
foreach (PlatformABI abi in Enum.GetValues(typeof(PlatformABI)))
|
|
||||||
{
|
|
||||||
string outputFile = $"{SettingsUtil.GeneratedCppDir}/ReversePInvokeMethodStub_{abi}.cpp";
|
|
||||||
|
|
||||||
List<ABIReversePInvokeMethodInfo> methods = analyzer.BuildABIMethods(abi);
|
|
||||||
Debug.Log($"GenerateReversePInvokeWrapper. abi:{abi} wraperCount:{methods.Sum(m => m.Count)} output:{outputFile}");
|
|
||||||
var generator = new Generator();
|
|
||||||
generator.Generate(templateCode, abi, methods, outputFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MethodBridgeGeneratorCommand.CleanIl2CppBuildCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 7db18e1736f593c4089c85d764cf8620
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
using HybridCLR.Editor.Installer;
|
using HybridCLR.Editor.BuildProcessors;
|
||||||
|
using HybridCLR.Editor.Installer;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using static UnityEngine.Networking.UnityWebRequest;
|
||||||
|
|
||||||
namespace HybridCLR.Editor.Commands
|
namespace HybridCLR.Editor.Commands
|
||||||
{
|
{
|
||||||
|
|
@ -15,7 +18,38 @@ namespace HybridCLR.Editor.Commands
|
||||||
[MenuItem("HybridCLR/Generate/AOTDlls", priority = 105)]
|
[MenuItem("HybridCLR/Generate/AOTDlls", priority = 105)]
|
||||||
public static void GenerateStripedAOTDlls()
|
public static void GenerateStripedAOTDlls()
|
||||||
{
|
{
|
||||||
GenerateStripedAOTDlls(EditorUserBuildSettings.activeBuildTarget, EditorUserBuildSettings.selectedBuildTargetGroup);
|
GenerateStripedAOTDlls(EditorUserBuildSettings.activeBuildTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BuildOptions GetBuildPlayerOptions(BuildTarget buildTarget)
|
||||||
|
{
|
||||||
|
BuildOptions options = BuildOptions.None;
|
||||||
|
bool development = EditorUserBuildSettings.development;
|
||||||
|
if (development)
|
||||||
|
{
|
||||||
|
options |= BuildOptions.Development;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorUserBuildSettings.allowDebugging && development)
|
||||||
|
{
|
||||||
|
options |= BuildOptions.AllowDebugging;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorUserBuildSettings.connectProfiler && (development || buildTarget == BuildTarget.WSAPlayer))
|
||||||
|
{
|
||||||
|
options |= BuildOptions.ConnectWithProfiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorUserBuildSettings.buildWithDeepProfilingSupport && development)
|
||||||
|
{
|
||||||
|
options |= BuildOptions.EnableDeepProfilingSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2021_2_OR_NEWER
|
||||||
|
options |= BuildOptions.CleanBuildCache;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetLocationPathName(string buildDir, BuildTarget target)
|
private static string GetLocationPathName(string buildDir, BuildTarget target)
|
||||||
|
|
@ -23,31 +57,42 @@ namespace HybridCLR.Editor.Commands
|
||||||
switch(target)
|
switch(target)
|
||||||
{
|
{
|
||||||
case BuildTarget.StandaloneWindows:
|
case BuildTarget.StandaloneWindows:
|
||||||
case BuildTarget.StandaloneWindows64: return $"{buildDir}/{target}";
|
case BuildTarget.StandaloneWindows64: return $"{buildDir}/{PlayerSettings.productName}.exe";
|
||||||
case BuildTarget.StandaloneOSX: return buildDir;
|
case BuildTarget.StandaloneOSX: return buildDir;
|
||||||
case BuildTarget.iOS: return buildDir;
|
case BuildTarget.iOS: return buildDir;
|
||||||
case BuildTarget.Android: return buildDir;
|
case BuildTarget.Android: return buildDir;
|
||||||
case BuildTarget.StandaloneLinux64: return buildDir;
|
case BuildTarget.StandaloneLinux64: return $"{buildDir}/{PlayerSettings.productName}";
|
||||||
default: return buildDir;
|
default: return buildDir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void GenerateStripedAOTDlls(BuildTarget target, BuildTargetGroup group)
|
public static void GenerateStripedAOTDlls(BuildTarget target)
|
||||||
{
|
{
|
||||||
string outputPath = $"{SettingsUtil.HybridCLRDataDir}/StrippedAOTDllsTempProj/{target}";
|
string outputPath = $"{SettingsUtil.HybridCLRDataDir}/StrippedAOTDllsTempProj/{target}";
|
||||||
BashUtil.RemoveDir(outputPath);
|
BashUtil.RemoveDir(outputPath);
|
||||||
|
|
||||||
var buildOptions = BuildOptions.BuildScriptsOnly;
|
var buildOptions = GetBuildPlayerOptions(target);
|
||||||
|
|
||||||
bool oldExportAndroidProj = EditorUserBuildSettings.exportAsGoogleAndroidProject;
|
bool oldExportAndroidProj = EditorUserBuildSettings.exportAsGoogleAndroidProject;
|
||||||
#if UNITY_EDITOR_OSX
|
#if UNITY_EDITOR_OSX
|
||||||
bool oldCreateSolution = UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject;
|
bool oldCreateSolution = UnityEditor.OSXStandalone.UserBuildSettings.createXcodeProject;
|
||||||
#elif UNITY_EDITOR_WIN
|
#elif UNITY_EDITOR_WIN
|
||||||
bool oldCreateSolution = UnityEditor.WindowsStandalone.UserBuildSettings.createSolution;
|
bool oldCreateSolution = UnityEditor.WindowsStandalone.UserBuildSettings.createSolution;
|
||||||
|
#endif
|
||||||
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
|
bool oldOpenHarmonyProj = EditorUserBuildSettings.exportAsOpenHarmonyProject;
|
||||||
#endif
|
#endif
|
||||||
bool oldBuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly;
|
bool oldBuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly;
|
||||||
|
|
||||||
|
string oldBuildLocation = EditorUserBuildSettings.GetBuildLocation(target);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CheckSettings.DisableMethodBridgeDevelopmentFlagChecking = true;
|
||||||
EditorUserBuildSettings.buildScriptsOnly = true;
|
EditorUserBuildSettings.buildScriptsOnly = true;
|
||||||
|
|
||||||
|
string location = GetLocationPathName(outputPath, target);
|
||||||
|
EditorUserBuildSettings.SetBuildLocation(target, location);
|
||||||
|
|
||||||
switch (target)
|
switch (target)
|
||||||
{
|
{
|
||||||
case BuildTarget.StandaloneWindows:
|
case BuildTarget.StandaloneWindows:
|
||||||
|
|
@ -65,25 +110,52 @@ namespace HybridCLR.Editor.Commands
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
|
case BuildTarget.HMIAndroid:
|
||||||
|
#endif
|
||||||
case BuildTarget.Android:
|
case BuildTarget.Android:
|
||||||
{
|
{
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
|
case BuildTarget.OpenHarmony:
|
||||||
|
{
|
||||||
|
EditorUserBuildSettings.exportAsOpenHarmonyProject = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"GenerateStripedAOTDlls build option:{buildOptions}");
|
||||||
|
|
||||||
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
|
BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions()
|
||||||
{
|
{
|
||||||
scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(),
|
scenes = EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(),
|
||||||
locationPathName = GetLocationPathName(outputPath, target),
|
locationPathName = location,
|
||||||
options = buildOptions,
|
options = buildOptions,
|
||||||
target = target,
|
target = target,
|
||||||
targetGroup = group,
|
targetGroup = BuildPipeline.GetBuildTargetGroup(target),
|
||||||
|
#if UNITY_SERVER
|
||||||
|
subtarget = (int)StandaloneBuildSubtarget.Server,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
var report = BuildPipeline.BuildPlayer(buildPlayerOptions);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
||||||
|
{
|
||||||
|
throw new Exception("GenerateStripedAOTDlls failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CheckSettings.DisableMethodBridgeDevelopmentFlagChecking = false;
|
||||||
EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly;
|
EditorUserBuildSettings.buildScriptsOnly = oldBuildScriptsOnly;
|
||||||
|
EditorUserBuildSettings.SetBuildLocation(target, oldBuildLocation);
|
||||||
|
|
||||||
switch (target)
|
switch (target)
|
||||||
{
|
{
|
||||||
case BuildTarget.StandaloneWindows:
|
case BuildTarget.StandaloneWindows:
|
||||||
|
|
@ -101,19 +173,24 @@ namespace HybridCLR.Editor.Commands
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
|
case BuildTarget.HMIAndroid:
|
||||||
|
#endif
|
||||||
case BuildTarget.Android:
|
case BuildTarget.Android:
|
||||||
{
|
{
|
||||||
EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj;
|
EditorUserBuildSettings.exportAsGoogleAndroidProject = oldExportAndroidProj;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
#if TUANJIE_2022_3_OR_NEWER
|
||||||
|
case BuildTarget.OpenHarmony:
|
||||||
if (report.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
|
|
||||||
{
|
{
|
||||||
Debug.LogError("GenerateStripedAOTDlls 失败");
|
EditorUserBuildSettings.exportAsOpenHarmonyProject = oldOpenHarmonyProj;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
Debug.Log($"GenerateStripedAOTDlls target:{target} group:{group} path:{outputPath}");
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug.Log($"GenerateStripedAOTDlls target:{target} path:{outputPath}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e60a8b17b0e23a94a8ae875716208030
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue