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.
- package/dist/async/index.js +162 -0
- package/dist/async/zeppos_timer.js +58 -0
- package/dist/audio/index.js +260 -0
- package/dist/config/index.js +57 -0
- package/dist/debug/index.js +8 -0
- package/dist/index.js +103 -0
- package/dist/platform/index.js +1 -0
- package/dist/plugins/basic_command/$.js +8 -0
- package/dist/plugins/basic_command/audio.js +40 -0
- package/dist/plugins/basic_command/basic.js +124 -0
- package/dist/plugins/basic_command/character.js +112 -0
- package/dist/plugins/basic_command/conditional.js +260 -0
- package/dist/plugins/basic_command/config.js +22 -0
- package/dist/plugins/basic_command/decorator.js +24 -0
- package/dist/plugins/basic_command/eval.js +67 -0
- package/dist/plugins/basic_command/img.js +249 -0
- package/dist/plugins/basic_command/index.js +22 -0
- package/dist/plugins/basic_command/menu.js +140 -0
- package/dist/plugins/global_gesture/index.js +25 -0
- package/dist/plugins/transform/animation.js +440 -0
- package/dist/plugins/transform/commands.js +38 -0
- package/dist/plugins/transform/example_profiles.js +32 -0
- package/dist/plugins/transform/hz_anime.js +211 -0
- package/dist/plugins/transform/index.js +93 -0
- package/dist/script/index.js +537 -0
- package/dist/script/readscript.js +15 -0
- package/dist/script/strtools.js +157 -0
- package/dist/storage/decorator.js +260 -0
- package/dist/storage/fs.js +96 -0
- package/dist/storage/index.js +442 -0
- package/dist/system/index.js +144 -0
- package/dist/ui/index.js +535 -0
- package/dist/utils/path.js +289 -0
- package/license.txt +202 -0
- package/package.json +26 -0
- package/src/async/index.ts +124 -0
- package/src/async/zeppos_timer.js +65 -0
- package/src/audio/index.ts +224 -0
- package/src/config/index.ts +80 -0
- package/src/debug/index.ts +11 -0
- package/src/index.ts +122 -0
- package/src/platform/index.ts +158 -0
- package/src/plugins/basic_command/$.ts +11 -0
- package/src/plugins/basic_command/audio.ts +53 -0
- package/src/plugins/basic_command/basic.ts +145 -0
- package/src/plugins/basic_command/character.ts +144 -0
- package/src/plugins/basic_command/conditional.ts +349 -0
- package/src/plugins/basic_command/config.ts +29 -0
- package/src/plugins/basic_command/decorator.ts +29 -0
- package/src/plugins/basic_command/eval.ts +88 -0
- package/src/plugins/basic_command/img.ts +317 -0
- package/src/plugins/basic_command/index.ts +24 -0
- package/src/plugins/basic_command/menu.ts +178 -0
- package/src/plugins/global_gesture/index.ts +29 -0
- package/src/plugins/transform/animation.ts +542 -0
- package/src/plugins/transform/commands.ts +53 -0
- package/src/plugins/transform/example_profiles.ts +36 -0
- package/src/plugins/transform/hz_anime.ts +214 -0
- package/src/plugins/transform/index.ts +141 -0
- package/src/plugins/transform/readme.md +1 -0
- package/src/script/index.ts +623 -0
- package/src/script/readscript.ts +17 -0
- package/src/script/strtools.ts +159 -0
- package/src/storage/decorator.ts +473 -0
- package/src/storage/fs.ts +104 -0
- package/src/storage/index.ts +541 -0
- package/src/system/index.ts +95 -0
- package/src/ui/index.ts +699 -0
- package/src/utils/path.js +338 -0
- package/tsconfig.json +111 -0
- package/types/async/index.d.ts +24 -0
- package/types/async/zeppos_timer.d.ts +14 -0
- package/types/audio/index.d.ts +64 -0
- package/types/config/index.d.ts +9 -0
- package/types/debug/index.d.ts +6 -0
- package/types/index.d.ts +41 -0
- package/types/platform/index.d.ts +134 -0
- package/types/plugins/basic_command/$.d.ts +2 -0
- package/types/plugins/basic_command/audio.d.ts +2 -0
- package/types/plugins/basic_command/basic.d.ts +3 -0
- package/types/plugins/basic_command/character.d.ts +2 -0
- package/types/plugins/basic_command/conditional.d.ts +2 -0
- package/types/plugins/basic_command/config.d.ts +2 -0
- package/types/plugins/basic_command/decorator.d.ts +2 -0
- package/types/plugins/basic_command/eval.d.ts +2 -0
- package/types/plugins/basic_command/img.d.ts +2 -0
- package/types/plugins/basic_command/index.d.ts +2 -0
- package/types/plugins/basic_command/menu.d.ts +2 -0
- package/types/plugins/global_gesture/index.d.ts +2 -0
- package/types/plugins/transform/animation.d.ts +131 -0
- package/types/plugins/transform/commands.d.ts +7 -0
- package/types/plugins/transform/example_profiles.d.ts +2 -0
- package/types/plugins/transform/hz_anime.d.ts +51 -0
- package/types/plugins/transform/index.d.ts +13 -0
- package/types/script/index.d.ts +123 -0
- package/types/script/readscript.d.ts +2 -0
- package/types/script/strtools.d.ts +31 -0
- package/types/storage/decorator.d.ts +41 -0
- package/types/storage/fs.d.ts +1 -0
- package/types/storage/index.d.ts +86 -0
- package/types/system/index.d.ts +35 -0
- package/types/ui/index.d.ts +167 -0
- 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
|
+
}
|