230 lines
6.4 kB
1
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
2
import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
3
import { processFind, testFind } from "@moonlight-mod/core/util/patch";
4
5
const webpackRequire = require as unknown as WebpackRequireType;
6
const cache = webpackRequire.c;
7
const modules = webpackRequire.m;
8
9
const logger = moonlight.getLogger("spacepack");
10
11
export const spacepack: Spacepack = {
12
require: webpackRequire,
13
modules,
14
cache,
15
16
inspect: (module: number | string) => {
17
if (typeof module === "number") {
18
module = module.toString();
19
}
20
21
if (module in moonlight.moonmap.modules) {
22
module = moonlight.moonmap.modules[module];
23
}
24
25
if (!(module in modules)) {
26
return null;
27
}
28
29
const func = modules[module];
30
if (func.__moonlight === true) {
31
return func;
32
}
33
34
const funcStr = func.toString();
35
36
return new Function(
37
"module",
38
"exports",
39
"require",
40
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${module}`
41
) as WebpackModuleFunc;
42
},
43
44
findByCode: (...args: (string | RegExp)[]) => {
45
const ret = Object.entries(modules)
46
.filter(([id, mod]) => !args.some((item) => !testFind(mod.toString(), processFind(item))))
47
.map(([id]) => {
48
//if (!(id in cache)) require(id);
49
//return cache[id];
50
51
let exports;
52
try {
53
exports = require(id);
54
} catch (e) {
55
logger.error(`findByCode: Error requiring module "${id}": `, args, e);
56
}
57
58
return {
59
id,
60
exports
61
};
62
})
63
.filter((item) => item !== null);
64
65
if (ret.length === 0) {
66
logger.warn("findByCode: Got zero results for", args, new Error().stack!.substring(5));
67
}
68
69
return ret;
70
},
71
72
findByExports: (...args: string[]) => {
73
return Object.entries(cache)
74
.filter(
75
([id, { exports }]) =>
76
!args.some(
77
(item) =>
78
!(
79
exports !== undefined &&
80
exports !== window &&
81
(exports?.[item] || exports?.default?.[item] || exports?.Z?.[item] || exports?.ZP?.[item])
82
)
83
)
84
)
85
.map((item) => item[1])
86
.reduce<WebpackModule[]>((prev, curr) => {
87
if (!prev.includes(curr)) prev.push(curr);
88
return prev;
89
}, []);
90
},
91
92
findObjectFromKey: (exports: Record<string, any>, key: string) => {
93
let ret = null;
94
let subKey;
95
if (key.indexOf(".") > -1) {
96
const splitKey = key.split(".");
97
key = splitKey[0];
98
subKey = splitKey[1];
99
}
100
for (const exportKey in exports) {
101
const obj = exports[exportKey];
102
if (obj && obj[key] !== undefined) {
103
if (subKey) {
104
if (obj[key][subKey]) {
105
ret = obj;
106
break;
107
}
108
} else {
109
ret = obj;
110
break;
111
}
112
}
113
}
114
115
if (ret == null) {
116
logger.warn("Failed to find object by key", key, "in", exports, new Error().stack!.substring(5));
117
}
118
119
return ret;
120
},
121
122
findObjectFromValue: (exports: Record<string, any>, value: any) => {
123
let ret = null;
124
for (const exportKey in exports) {
125
const obj = exports[exportKey];
126
// eslint-disable-next-line eqeqeq
127
if (obj == value) {
128
ret = obj;
129
break;
130
}
131
for (const subKey in obj) {
132
// eslint-disable-next-line eqeqeq
133
if (obj && obj[subKey] == value) {
134
ret = obj;
135
break;
136
}
137
}
138
}
139
140
if (ret == null) {
141
logger.warn("Failed to find object by value", value, "in", exports, new Error().stack!.substring(5));
142
}
143
144
return ret;
145
},
146
147
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
148
let ret = null;
149
for (const exportKey in exports) {
150
const obj = exports[exportKey];
151
// eslint-disable-next-line eqeqeq
152
if (obj && obj[key] == value) {
153
ret = obj;
154
break;
155
}
156
}
157
158
if (ret == null) {
159
logger.warn(
160
"Failed to find object by key value pair",
161
key,
162
value,
163
"in",
164
exports,
165
new Error().stack!.substring(5)
166
);
167
}
168
169
return null;
170
},
171
172
findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
173
const ret =
174
Object.entries(exports).filter(
175
([index, func]) =>
176
typeof func === "function" && !strings.some((query) => !testFind(func.toString(), processFind(query)))
177
)?.[0]?.[1] ?? null;
178
179
if (ret == null) {
180
logger.warn("Failed to find function by strings", strings, "in", exports, new Error().stack!.substring(5));
181
}
182
183
return ret;
184
},
185
186
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
187
chunk = processFind(chunk);
188
module = processFind(module);
189
190
const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
191
if (mod.length < 1) {
192
logger.warn("lazyLoad: Module find failed", find, chunk, module, new Error().stack!.substring(5));
193
return Promise.reject("Module find failed");
194
}
195
196
const findId = mod[0].id;
197
const findCode = webpackRequire.m[findId].toString().replace(/\n/g, "");
198
199
let chunkIds;
200
if (chunk.flags.includes("g")) {
201
chunkIds = [...findCode.matchAll(chunk)].map(([, id]) => id);
202
} else {
203
const match = findCode.match(chunk);
204
if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
205
}
206
207
if (!chunkIds || chunkIds.length === 0) {
208
logger.warn("lazyLoad: Chunk ID match failed", find, chunk, module, new Error().stack!.substring(5));
209
return Promise.reject("Chunk ID match failed");
210
}
211
212
const moduleId = findCode.match(module)?.[1];
213
if (!moduleId) {
214
logger.warn("lazyLoad: Module ID match failed", find, chunk, module, new Error().stack!.substring(5));
215
return Promise.reject("Module ID match failed");
216
}
217
218
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
219
},
220
221
filterReal: (modules: WebpackModule[]) => {
222
return modules.filter((module) => module.id.toString().match(/^\d+$/));
223
}
224
};
225
226
if (moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true) {
227
window.spacepack = spacepack;
228
}
229
230
export default spacepack;
231