hzengine-core 0.1.2-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/async/index.js +162 -0
  2. package/dist/async/zeppos_timer.js +58 -0
  3. package/dist/audio/index.js +260 -0
  4. package/dist/config/index.js +57 -0
  5. package/dist/debug/index.js +8 -0
  6. package/dist/index.js +103 -0
  7. package/dist/platform/index.js +1 -0
  8. package/dist/plugins/basic_command/$.js +8 -0
  9. package/dist/plugins/basic_command/audio.js +40 -0
  10. package/dist/plugins/basic_command/basic.js +124 -0
  11. package/dist/plugins/basic_command/character.js +112 -0
  12. package/dist/plugins/basic_command/conditional.js +260 -0
  13. package/dist/plugins/basic_command/config.js +22 -0
  14. package/dist/plugins/basic_command/decorator.js +24 -0
  15. package/dist/plugins/basic_command/eval.js +67 -0
  16. package/dist/plugins/basic_command/img.js +249 -0
  17. package/dist/plugins/basic_command/index.js +22 -0
  18. package/dist/plugins/basic_command/menu.js +140 -0
  19. package/dist/plugins/global_gesture/index.js +25 -0
  20. package/dist/plugins/transform/animation.js +440 -0
  21. package/dist/plugins/transform/commands.js +38 -0
  22. package/dist/plugins/transform/example_profiles.js +32 -0
  23. package/dist/plugins/transform/hz_anime.js +211 -0
  24. package/dist/plugins/transform/index.js +93 -0
  25. package/dist/script/index.js +537 -0
  26. package/dist/script/readscript.js +15 -0
  27. package/dist/script/strtools.js +157 -0
  28. package/dist/storage/decorator.js +260 -0
  29. package/dist/storage/fs.js +96 -0
  30. package/dist/storage/index.js +442 -0
  31. package/dist/system/index.js +144 -0
  32. package/dist/ui/index.js +535 -0
  33. package/dist/utils/path.js +289 -0
  34. package/license.txt +202 -0
  35. package/package.json +26 -0
  36. package/src/async/index.ts +124 -0
  37. package/src/async/zeppos_timer.js +65 -0
  38. package/src/audio/index.ts +224 -0
  39. package/src/config/index.ts +80 -0
  40. package/src/debug/index.ts +11 -0
  41. package/src/index.ts +122 -0
  42. package/src/platform/index.ts +158 -0
  43. package/src/plugins/basic_command/$.ts +11 -0
  44. package/src/plugins/basic_command/audio.ts +53 -0
  45. package/src/plugins/basic_command/basic.ts +145 -0
  46. package/src/plugins/basic_command/character.ts +144 -0
  47. package/src/plugins/basic_command/conditional.ts +349 -0
  48. package/src/plugins/basic_command/config.ts +29 -0
  49. package/src/plugins/basic_command/decorator.ts +29 -0
  50. package/src/plugins/basic_command/eval.ts +88 -0
  51. package/src/plugins/basic_command/img.ts +317 -0
  52. package/src/plugins/basic_command/index.ts +24 -0
  53. package/src/plugins/basic_command/menu.ts +178 -0
  54. package/src/plugins/global_gesture/index.ts +29 -0
  55. package/src/plugins/transform/animation.ts +542 -0
  56. package/src/plugins/transform/commands.ts +53 -0
  57. package/src/plugins/transform/example_profiles.ts +36 -0
  58. package/src/plugins/transform/hz_anime.ts +214 -0
  59. package/src/plugins/transform/index.ts +141 -0
  60. package/src/plugins/transform/readme.md +1 -0
  61. package/src/script/index.ts +623 -0
  62. package/src/script/readscript.ts +17 -0
  63. package/src/script/strtools.ts +159 -0
  64. package/src/storage/decorator.ts +473 -0
  65. package/src/storage/fs.ts +104 -0
  66. package/src/storage/index.ts +541 -0
  67. package/src/system/index.ts +95 -0
  68. package/src/ui/index.ts +699 -0
  69. package/src/utils/path.js +338 -0
  70. package/tsconfig.json +111 -0
  71. package/types/async/index.d.ts +24 -0
  72. package/types/async/zeppos_timer.d.ts +14 -0
  73. package/types/audio/index.d.ts +64 -0
  74. package/types/config/index.d.ts +9 -0
  75. package/types/debug/index.d.ts +6 -0
  76. package/types/index.d.ts +41 -0
  77. package/types/platform/index.d.ts +134 -0
  78. package/types/plugins/basic_command/$.d.ts +2 -0
  79. package/types/plugins/basic_command/audio.d.ts +2 -0
  80. package/types/plugins/basic_command/basic.d.ts +3 -0
  81. package/types/plugins/basic_command/character.d.ts +2 -0
  82. package/types/plugins/basic_command/conditional.d.ts +2 -0
  83. package/types/plugins/basic_command/config.d.ts +2 -0
  84. package/types/plugins/basic_command/decorator.d.ts +2 -0
  85. package/types/plugins/basic_command/eval.d.ts +2 -0
  86. package/types/plugins/basic_command/img.d.ts +2 -0
  87. package/types/plugins/basic_command/index.d.ts +2 -0
  88. package/types/plugins/basic_command/menu.d.ts +2 -0
  89. package/types/plugins/global_gesture/index.d.ts +2 -0
  90. package/types/plugins/transform/animation.d.ts +131 -0
  91. package/types/plugins/transform/commands.d.ts +7 -0
  92. package/types/plugins/transform/example_profiles.d.ts +2 -0
  93. package/types/plugins/transform/hz_anime.d.ts +51 -0
  94. package/types/plugins/transform/index.d.ts +13 -0
  95. package/types/script/index.d.ts +123 -0
  96. package/types/script/readscript.d.ts +2 -0
  97. package/types/script/strtools.d.ts +31 -0
  98. package/types/storage/decorator.d.ts +41 -0
  99. package/types/storage/fs.d.ts +1 -0
  100. package/types/storage/index.d.ts +86 -0
  101. package/types/system/index.d.ts +35 -0
  102. package/types/ui/index.d.ts +167 -0
  103. package/types/utils/path.d.ts +84 -0
@@ -0,0 +1,104 @@
1
+ // import * as hmApp from "@zos/app";
2
+ // import * as hmFS from "@zos/fs";
3
+ // import Path ;
4
+ // function getAppDir(appId = (hmApp.getPackageInfo() as any).appId) {
5
+ // let str = appId.toString(16);
6
+ // switch (str.length) {
7
+ // case 1:
8
+ // return `0000000${str}`.toUpperCase();
9
+ // case 2:
10
+ // return `000000${str}`.toUpperCase();
11
+ // case 3:
12
+ // return `00000${str}`.toUpperCase();
13
+ // case 4:
14
+ // return `0000${str}`.toUpperCase();
15
+ // case 5:
16
+ // return `000${str}`.toUpperCase();
17
+ // case 6:
18
+ // return `00${str}`.toUpperCase();
19
+ // case 7:
20
+ // return `0${str}`.toUpperCase();
21
+ // case 8:
22
+ // return `${str}`.toUpperCase();
23
+ // }
24
+ // }
25
+
26
+ // function readdirAssetsSync(option: { path: string }): string[] | undefined {
27
+ // return hmFS.readdirSync({
28
+ // path: fromDataToAssetsPath(option.path),
29
+ // });
30
+ // }
31
+
32
+ // export function isFileSync(option: { path: string }) {
33
+ // let code = hmFS.openSync({ path: option.path });
34
+ // if (code >= 0) {
35
+ // hmFS.closeSync({ fd: code });
36
+ // return true;
37
+ // } else {
38
+ // return false;
39
+ // }
40
+ // }
41
+
42
+ // function isFileAssetsSync(option: { path: string }) {
43
+ // // console.log("path=" + option.path);
44
+
45
+ // let code = hmFS.openAssetsSync({ path: option.path });
46
+ // if (code >= 0) {
47
+ // hmFS.closeSync({ fd: code });
48
+ // return true;
49
+ // } else {
50
+ // return false;
51
+ // }
52
+ // }
53
+
54
+ // /**
55
+ // * 将基于assets的文件路径转换为基于data的文件路径
56
+ // */
57
+ // function fromDataToAssetsPath(path: string) {
58
+ // return Path.join(`../../${getAppDir()}/assets`, path);
59
+ // }
60
+
61
+ // function writeFileAssetsSync(opt: {
62
+ // path: string;
63
+ // data: string | ArrayBuffer | DataView;
64
+ // options?: hmFS.writeFileSync.Options;
65
+ // }) {
66
+ // // console.log("write path="+opt.path);
67
+ // let fd = hmFS.openAssetsSync({
68
+ // path: opt.path,
69
+ // flag: hmFS.O_WRONLY | hmFS.O_CREAT,
70
+ // });
71
+ // if (fd < 0) throw "Open Assets File Failed code=" + fd;
72
+ // let buf = opt.data;
73
+ // if (buf instanceof DataView) {
74
+ // buf = buf.buffer; // TODO maybe error
75
+ // }
76
+ // if (typeof buf === "string") buf = Buffer.from(buf).buffer;
77
+
78
+ // let res = hmFS.writeSync({
79
+ // fd,
80
+ // buffer: buf,
81
+ // });
82
+ // hmFS.closeSync({ fd });
83
+ // return res;
84
+ // }
85
+
86
+ // function readFileAssetsSync(opt: {
87
+ // path: string;
88
+ // options?: hmFS.readFileSync.Options;
89
+ // }) {
90
+ // // console.log("read path="+opt.path);
91
+ // let fd = hmFS.openAssetsSync({ path: opt.path, flag: hmFS.O_RDONLY });
92
+ // if (fd < 0) throw "Open Assets File Failed code=" + fd;
93
+ // let size = hmFS.statAssetsSync({ path: opt.path })!.size;
94
+ // let arrbuf = new ArrayBuffer(size);
95
+ // let res = hmFS.readSync({ fd, buffer: arrbuf });
96
+ // console.log("read size=" + res);
97
+
98
+ // hmFS.closeSync({ fd });
99
+ // if (opt.options && typeof opt.options.encoding === "string") {
100
+ // return Buffer.from(arrbuf).toString(opt.options.encoding);
101
+ // } else {
102
+ // return arrbuf;
103
+ // }
104
+ // }
@@ -0,0 +1,541 @@
1
+ // / <reference types="@zeppos/device-types" />
2
+ import { HZEngineCore, Platform } from "../index.js";
3
+ // import * as this._core.platform from "@zos/fs";
4
+ import Path from "../utils/path.js";
5
+ // import { isFileSync } from "./fs.js";
6
+
7
+ export class Storage{
8
+ constructor(private _core: HZEngineCore) {}
9
+
10
+ projectRoot: string | null = null;
11
+ cacheRoot: string | null = null;
12
+ saveRoot: string | null = null;
13
+ preloadedData: NonNullable<any> | null = null;
14
+ packageData: NonNullable<any> | null = null;
15
+ loadProject(options: {
16
+ projectPath: string;
17
+ cachePath: string;
18
+ savePath: string;
19
+ }) {
20
+ this._core.emit("beforeLoadProject");
21
+ if (!this._core.platform.readdirSync({ path: options.projectPath })) {
22
+ throw "Dir not exist";
23
+ }
24
+ this.projectRoot = options.projectPath;
25
+ this.cacheRoot = options.cachePath;
26
+ this.saveRoot = options.savePath;
27
+
28
+ this.loadPackageData();
29
+ this.preload();
30
+
31
+ this._core.emit("afterLoadProject");
32
+ }
33
+
34
+ loadPackageData() {
35
+ if (!this.projectRoot) throw "projectDir is null";
36
+ this._core.debug.log(
37
+ `loadPackageData ${this.projectRoot} ${Path.join(
38
+ this.projectRoot,
39
+ "hz_package.json"
40
+ )}`
41
+ );
42
+
43
+ if (
44
+ !this._core.platform.statSync({
45
+ path: Path.join(this.projectRoot, "hz_package.json"),
46
+ })
47
+ ) {
48
+ throw "HZEngine Package File (hz_package.json) not exist";
49
+ }
50
+ this.packageData = JSON.parse(
51
+ this._core.platform.readFileSync({
52
+ path: Path.join(this.projectRoot, "hz_package.json"),
53
+ options: { encoding: "utf8" },
54
+ }) as string
55
+ );
56
+ }
57
+
58
+ // Storage Data
59
+
60
+ /**
61
+ * 全局数据
62
+ * 其中的数据不会跟随存档保存,而是直接存储在全局数据文件中
63
+ * 如:设置、CG解锁情况等
64
+ */
65
+ private _globalData: NonNullable<Storage.JSONValue> | null = null;
66
+ get globalData() {
67
+ if (!this._globalData) {
68
+ this.loadGlobalData();
69
+ }
70
+ if (this._globalData == null) throw `[HZEngine] GlobalData is null`;
71
+ return this._globalData;
72
+ }
73
+ /**
74
+ * alias globalData
75
+ */
76
+ get gd() {
77
+ return this.globalData;
78
+ }
79
+
80
+ /**
81
+ * 存档数据
82
+ * 其中的数据会跟随存档保存
83
+ * 如:脚本执行位置即调用栈,攻略度等
84
+ */
85
+ private _archiveData: NonNullable<Storage.JSONValue> | null = null;
86
+ get archiveData(): NonNullable<Storage.JSONValue> {
87
+ if (!this._archiveData) {
88
+ this.loadArchiveData();
89
+ }
90
+ if (this._archiveData == null) throw `[HZEngine] ArchiveData is null`;
91
+ return this._archiveData;
92
+ }
93
+ /**
94
+ * alias archiveData
95
+ */
96
+ get sd() {
97
+ return this.archiveData;
98
+ }
99
+
100
+ loadGlobalData() {
101
+ if (!this.saveRoot) {
102
+ throw "saveDir is null, please loadProject first";
103
+ }
104
+ this._core.emit("beforeLoadGlobalData");
105
+ if (
106
+ this._core.platform.statSync({
107
+ path: Path.join(this.saveRoot, "globalData.json"),
108
+ })
109
+ ) {
110
+ this._globalData = JSON.parse(
111
+ this._core.platform.readFileSync({
112
+ path: Path.join(this.saveRoot, "globalData.json"),
113
+ options: {
114
+ encoding: "utf8",
115
+ },
116
+ }) as string
117
+ );
118
+ if (this._globalData == null) {
119
+ this._globalData = {}; // TODO initial GlobalData value
120
+ this._core.emit("initGlobalData");
121
+ }
122
+ } else {
123
+ this._core.debug.log(`globalData.json not exist, create it.`);
124
+ this._globalData = {}; // Initial GlobalData value
125
+ this._core.emit("initGlobalData");
126
+ this._core.platform.writeFileSync({
127
+ path: Path.join(this.saveRoot, "globalData.json"),
128
+ data: JSON.stringify(this._globalData),
129
+ });
130
+ }
131
+ this._core.emit("afterLoadGlobalData");
132
+ }
133
+
134
+ /**
135
+ * 保存全局数据
136
+ * 可以多次調用,實際上會異步儲存,也就是在一個宏任務中即使調用多次,也只會在宏任務結束後儲存一次
137
+ */
138
+ private _saveGlobalDataTimerId: number | null = null;
139
+ saveGlobalData() {
140
+ if (!this.projectRoot) {
141
+ throw "projectDir is null, please loadProject first";
142
+ }
143
+ if (this._saveGlobalDataTimerId) return;
144
+ this._saveGlobalDataTimerId = setTimeout(() => {
145
+ this._saveGlobalDataTimerId = null;
146
+ if (!this.projectRoot) {
147
+ throw "projectDir is null, please loadProject first";
148
+ }
149
+ this._core.emit("beforeSaveGlobalData");
150
+ let res = this._core.platform.writeFileSync({
151
+ path: Path.join(this.saveRoot!, "globalData.json"),
152
+ data: JSON.stringify(this._globalData),
153
+ }) as unknown as number; // TODO
154
+ if (res < 0)
155
+ throw `[HZEngine] save globalData to globalData.json failed, code = ${res}`;
156
+ this._core.debug.log(`save globalData to globalData.json`);
157
+ this._core.emit("afterSaveGlobalData");
158
+ }, 0) as unknown as number;
159
+ }
160
+
161
+ loadArchiveData(archiveFile?: string) {
162
+ this._core.emit("beforeLoadArchive");
163
+ if (archiveFile) {
164
+ if (!this.saveRoot) throw `saveRoot is null, please loadProject first`;
165
+ if (
166
+ !this._core.platform.statSync({
167
+ path: Path.join(this.saveRoot, archiveFile),
168
+ })
169
+ ) {
170
+ throw `Archive [${archiveFile}] not exist`;
171
+ }
172
+ let archiveData: Storage.JSONValue = JSON.parse(
173
+ this._core.platform.readFileSync({
174
+ path: Path.join(this.saveRoot, archiveFile),
175
+ options: {
176
+ encoding: "utf8",
177
+ },
178
+ }) as string
179
+ );
180
+ if (archiveData == null) throw `[HZEngine] ArchiveData is null`;
181
+ this._archiveData = archiveData;
182
+ this._core.debug.log(`load archiveData from ${archiveFile}`);
183
+ this._core.emit("afterLoadArchive");
184
+ } else {
185
+ this._core.debug.log(`load archiveData from empty template`);
186
+ this._archiveData = {};
187
+ this._core.emit("initArchiveData");
188
+ }
189
+ }
190
+
191
+ _saveArchiveDataTimerId: number | null = null;
192
+ /**
193
+ * 保存存档数据
194
+ * 可以多次調用,實際上會異步儲存,也就是在一個宏任務中即使調用多次,也只會在宏任務結束後儲存一次
195
+ * @param archiveFile 存档文件目錄及名字
196
+ */
197
+ saveArchiveData(archiveFile: string, immediate = false) {
198
+ if (!this.saveRoot) throw `saveRoot is null, please loadProject first`;
199
+ this._core.emit("beforeSaveArchive");
200
+ this._core.debug.log("Will save archiveData to " + archiveFile);
201
+ let saveFunc = () => {
202
+ this._core.debug.log("Saving archiveData to " + archiveFile);
203
+
204
+ if (!this.saveRoot) throw `projectDir is null, please loadProject first`;
205
+ let res = this._core.platform.writeFileSync({
206
+ path: Path.join(this.saveRoot!, archiveFile),
207
+ data: JSON.stringify(this._archiveData),
208
+ }) as unknown as number; //TODO
209
+ if (res < 0)
210
+ throw `[HZEngine] save archiveData to ${archiveFile} failed, code = ${res}`;
211
+ this._core.debug.log(`Save archiveData to ${archiveFile}`);
212
+
213
+ this._core.emit("afterSaveArchive");
214
+ };
215
+ if (immediate) {
216
+ saveFunc();
217
+ if (this._saveArchiveDataTimerId) {
218
+ clearTimeout(this._saveArchiveDataTimerId);
219
+ this._saveArchiveDataTimerId = null;
220
+ }
221
+ } else
222
+ this._saveArchiveDataTimerId = setTimeout(() => {
223
+ this._saveArchiveDataTimerId = null;
224
+ saveFunc();
225
+ }, 0) as unknown as number;
226
+ }
227
+
228
+ getSaveableData(
229
+ data: Storage.JSONValue,
230
+ auto_correct: boolean,
231
+ ...key_chain: string[]
232
+ ): NonNullable<Storage.JSONValue> {
233
+ let obj = data;
234
+
235
+ // if(obj == null) throw `[HZEngine] saveable data is null`
236
+ for (let key of key_chain) {
237
+ if (obj == null) throw Error(`[HZEngine] saveable data is null`);
238
+ if (typeof obj !== "object")
239
+ throw Error(`[HZEngine] saveable data is not object`);
240
+ if (Array.isArray(obj)) throw Error(`[HZEngine] saveable data is array`);
241
+ if (!obj[key]) {
242
+ if (auto_correct) {
243
+ obj[key] = {};
244
+ } else throw Error(`[HZEngine] saveable data key ${key} not exist`);
245
+ }
246
+ obj = obj[key];
247
+ }
248
+ if (obj == null) throw Error(`[HZEngine] saveable data result obj is null`);
249
+ // if (typeof obj !== "object")
250
+ // throw Error(`[HZEngine] saveable data result obj is not array or object`);
251
+ // if (Array.isArray(obj)) throw Error(`[HZEngine] saveable data result is an array, key_chain = ${key_chain.join(".")}, res = ${JSON.stringify(obj)}`);
252
+ return obj;
253
+ }
254
+
255
+ setSaveableData(
256
+ data: Storage.JSONValue,
257
+ auto_correct: boolean,
258
+ value: Storage.JSONValue,
259
+ ...key_chain: string[]
260
+ ) {
261
+ this._core.debug.log(
262
+ `setSaveableData ${key_chain} => ${JSON.stringify(value)}`
263
+ );
264
+
265
+ if (key_chain.length == 0) throw `key_chain is empty`;
266
+ let parentObj = this.getSaveableData(
267
+ data,
268
+ auto_correct,
269
+ ...key_chain.slice(0, -1)
270
+ );
271
+
272
+ if (parentObj == null) throw `[HZEngine] saveable data is null`;
273
+ if (typeof parentObj !== "object")
274
+ throw `[HZEngine] saveable data is not object`;
275
+ if (Array.isArray(parentObj)) throw `[HZEngine] saveable data is array`;
276
+ parentObj[key_chain[key_chain.length - 1]] = value;
277
+ }
278
+
279
+ checkSaveableData(data: Storage.JSONValue, ...key_chain: string[]) {
280
+ return this.getSaveableData(data, false, ...key_chain);
281
+ }
282
+
283
+ // Preload
284
+
285
+ preload() {
286
+ if (!this.cacheRoot) {
287
+ throw "cacheRoot is null, please loadProject first";
288
+ }
289
+
290
+ // writeFileSync({path: "data://test.json", data: "awa", options: {encoding: "utf8"}});
291
+
292
+ if (
293
+ this._core.platform.statSync({
294
+ path: Path.join(this.cacheRoot, "preloaded.json"),
295
+ })
296
+ ) {
297
+ // 已经预加载过了,退出
298
+ this.preloadedData = JSON.parse(
299
+ this._core.platform.readFileSync({
300
+ path: Path.join(this.cacheRoot, "preloaded.json"),
301
+ options: {
302
+ encoding: "utf8",
303
+ },
304
+ }) as string
305
+ );
306
+ return;
307
+ }
308
+
309
+ this.preloadedData = {
310
+ script: {
311
+ labelMap: {},
312
+ hzsInfoMap: {},
313
+ },
314
+ image: {
315
+ nameMap: {},
316
+ },
317
+ animation: {
318
+ profileMap: {},
319
+ },
320
+ };
321
+
322
+ this.preloadScript();
323
+ this.preloadImage();
324
+ this.preloadAnimation();
325
+
326
+ // console.log(JSON.stringify(this.preloadedData));
327
+
328
+ this._core.platform.writeFileSync({
329
+ path: Path.join(this.cacheRoot, "preloaded.json"),
330
+ data: JSON.stringify(this.preloadedData),
331
+ });
332
+
333
+ // console.log(
334
+ // `${Path.join(this.projectDir, "preloaded.json")} = ${readFileSync({
335
+ // path: Path.join(this.projectDir, "preloaded.json"),
336
+ // options:{encoding:"utf8"}
337
+ // })}`
338
+ // );
339
+ }
340
+ /**
341
+ * 预加载脚本
342
+ * 遍历出所有hzs文件和所有label,建立map
343
+ */
344
+ preloadScript() {
345
+ // TODO
346
+ // 记录脚本label的位置
347
+ // 这里的index是以0开始计数的行数
348
+ let labelMap: Record<string, [path: string, index: number]> =
349
+ this.preloadedData.script.labelMap;
350
+ let scriptDir = Path.join(this.projectRoot!, "script");
351
+
352
+ let hzsInfoMap: Record<string, HzsInfo> =
353
+ this.preloadedData.script.hzsInfoMap;
354
+ if (!this._core.platform.readdirSync({ path: scriptDir }))
355
+ throw "项目文件夹中script文件夹不存在";
356
+
357
+
358
+ /**
359
+ * 1. 预加载所有的label并检查冲突
360
+ * 2. 记录所有脚本文件的行数
361
+ */
362
+ const preloadHzs = (path: string) => {
363
+ // let fd = this._core.platform.openSync({ path });
364
+ // if (fd < 0) throw "Fd<0";
365
+ // let size = this._core.platform.statSync({ path })!.size;
366
+ // let arrbuf = new ArrayBuffer(size);
367
+ // this._core.platform.readSync({ fd, buffer: arrbuf });
368
+ // let buffer = Buffer.from(arrbuf);
369
+ // let contentStr = buffer.toString();
370
+ let contentStr = this._core.platform.readFileSync({ path, options: { encoding: "utf8" }}) as string;
371
+ let contentLines = contentStr.split("\n");
372
+ let totalLines = contentLines.length;
373
+ hzsInfoMap[path] = { totalLines };
374
+ for (let i = 0; i < totalLines; ++i) {
375
+ let line = contentLines[i].trim();
376
+ if (line.startsWith("*")) {
377
+ let len = line.length,
378
+ p = 1,
379
+ q;
380
+ while (p < len && line.charAt(p) === " ") ++p;
381
+ if (p === len)
382
+ throw `Lost Label Name at file(${path}) line(${i + 1})`;
383
+ q = p;
384
+ while (q < len && line.charAt(q) !== " ") ++q;
385
+ // [p, q)
386
+ let label = line.slice(p, q);
387
+
388
+ if (labelMap[label]) {
389
+ throw `Label name "${label}" conflict : \
390
+ at [${labelMap[label][0]}(line ${labelMap[label][1]})] \
391
+ [${path}(line ${i + 1})]`;
392
+ }
393
+
394
+ labelMap[label] = [path, i];
395
+ }
396
+ }
397
+ }
398
+
399
+ // 遍历所有hzs文件
400
+ const traverseScript = (path: string) => {
401
+ let dirs = this._core.platform.readdirSync({ path });
402
+ // console.log(dirs);
403
+
404
+ for (let dir of dirs!) {
405
+ let subpath = Path.join(path, dir);
406
+ if (this._core.platform.isFileSync({ path: subpath })) {
407
+ // 是文件
408
+ if (dir.endsWith(".hzs")) {
409
+ preloadHzs(subpath);
410
+ }
411
+ } else {
412
+ // 是目录
413
+ traverseScript(subpath);
414
+ }
415
+ }
416
+ }
417
+ traverseScript(scriptDir);
418
+
419
+
420
+ }
421
+ /**
422
+ * 预加载资源
423
+ * 遍历所有png文件,计算对应的name key,建立map
424
+ */
425
+ preloadImage() {
426
+ let nameMap: Record<string, [path: string]> =
427
+ this.preloadedData.image.nameMap;
428
+ let imageDir = Path.join(this.projectRoot!, "image");
429
+
430
+ if (!this._core.platform.readdirSync({ path: imageDir }))
431
+ throw "项目文件夹中image文件夹不存在";
432
+ /**
433
+ * 1. 预加载所有的image并检查冲突
434
+ * 2. 记录所有image的name key和路径
435
+ */
436
+ function preloadImage(path: string) {
437
+ let raw_name = Path.parse(path).name;
438
+ let name_key = raw_name
439
+ .trim()
440
+ .replace("_", " ")
441
+ .replace(/ +/, " ")
442
+ .toLowerCase();
443
+ if (nameMap[name_key])
444
+ throw `Image name key conflict [${name_key}], at file [${path}] and [${nameMap[name_key]}]`;
445
+ nameMap[name_key] = [path];
446
+ }
447
+ // 遍历所有hzs文件
448
+ const traverseImage = (path: string) => {
449
+ let dirs = this._core.platform.readdirSync({ path });
450
+ // console.log(dirs);
451
+
452
+ for (let dir of dirs!) {
453
+ let subpath = Path.join(path, dir);
454
+ if (this._core.platform.isFileSync({ path: subpath })) {
455
+ // 是文件
456
+ if (dir.endsWith(".png")) {
457
+ preloadImage(subpath);
458
+ }
459
+ } else {
460
+ // 是目录
461
+ traverseImage(subpath);
462
+ }
463
+ }
464
+ }
465
+ traverseImage(imageDir);
466
+
467
+
468
+ // console.log(
469
+ // `Preloaded image: ${JSON.stringify(this.preloadedData.image.nameMap)}`
470
+ // );
471
+ }
472
+
473
+ /**
474
+ * 預加載動畫profile
475
+ * 遍歷animation文件夾下的所有json文件,以文件名為key,json内容為value
476
+ */
477
+ preloadAnimation() {
478
+ let profileMap: Record<string, [path: string]> =
479
+ this.preloadedData.animation.profileMap;
480
+
481
+ let animationDir = Path.join(this.projectRoot!, "animation");
482
+ if (!this._core.platform.readdirSync({ path: animationDir }))
483
+ throw "项目文件夹中animation文件夹不存在";
484
+
485
+
486
+ function preloadAnimation(path: string) {
487
+ let raw_name = Path.parse(path).name;
488
+ let name_key = raw_name.trim().replace(/ +/, "_");
489
+ if (profileMap[name_key])
490
+ throw `Animation profile name key conflict [${name_key}], at file [${path}] and [${profileMap[name_key]}]`;
491
+ profileMap[name_key] = [path];
492
+ }
493
+ const traverseAnimation = (path: string) => {
494
+ let dirs = this._core.platform.readdirSync({ path });
495
+ // console.log(dirs);
496
+
497
+ for (let dir of dirs!) {
498
+ let subpath = Path.join(path, dir);
499
+ if (this._core.platform.isFileSync({ path: subpath })) {
500
+ // 是文件
501
+ if (dir.endsWith(".json")) {
502
+ preloadAnimation(subpath);
503
+ }
504
+ } else {
505
+ // 是目录
506
+ traverseAnimation(subpath);
507
+ }
508
+ }
509
+ }
510
+ traverseAnimation(animationDir);
511
+
512
+ }
513
+ // Decorator Field
514
+ // _archiveStateSetterRegisteredList: Set<string> = new Set();
515
+ // _archiveStateGetterRegisteredList: Set<string> = new Set();
516
+ }
517
+
518
+ // 记录脚本文件信息
519
+ export declare type HzsInfo = {
520
+ totalLines: number;
521
+ };
522
+
523
+ export namespace Storage {
524
+ export type JSONBaseType = number | string | boolean | null;
525
+ export type JSONValue =
526
+ | JSONBaseType
527
+ | { [key: string]: JSONValue }
528
+ | JSONValue[];
529
+
530
+ export type Saveable<T> =
531
+ | {
532
+ [P in keyof T]: T[P] extends JSONValue
533
+ ? T[P]
534
+ : T[P] extends NotAssignableToJson
535
+ ? never
536
+ : Saveable<T[P]>;
537
+ }
538
+ | JSONValue[]
539
+ | JSONValue;
540
+ type NotAssignableToJson = bigint | symbol | Function;
541
+ }