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,29 @@
1
+ import { HZEngineCore } from "../../index.js";
2
+ import Path from "../../utils/path.js";
3
+
4
+ export function config_command(core: HZEngineCore) {
5
+ // set command: set <key> <value>
6
+ core.script.use((ctx, next) => {
7
+ if (
8
+ ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "set"
9
+ )
10
+ return next();
11
+ if (ctx.slicedArgs.length !== 3)
12
+ throw `Set Command: incorrect amount of args`;
13
+
14
+ let key = ctx.slicedArgs[1].str;
15
+ let val: any = ctx.slicedArgs[2].str;
16
+
17
+ if(!ctx.slicedArgs[2].isQuoted) {
18
+ if(val === "true" || val === "false") {
19
+ val = val === "true";
20
+ }
21
+ else if(!isNaN(val)) {
22
+ val = Number(val);
23
+ }
24
+ else throw `Set Command: value type not supported`;
25
+ }
26
+
27
+ core.config.setConfig(key, val);
28
+ });
29
+ }
@@ -0,0 +1,29 @@
1
+ import { HZEngineCore } from "../../index.js";
2
+ import { splitStr2Objs, splitStr2Strs } from "../../script/strtools.js";
3
+
4
+ export function decorator_module(core: HZEngineCore) {
5
+ core.script.use((ctx, next) => {
6
+ if (
7
+ !ctx.slicedArgs[0].isSquared
8
+ )
9
+ return next();
10
+
11
+ let decorator = ctx.slicedArgs[0].str.toLowerCase();
12
+
13
+ switch (splitStr2Strs(decorator).join("").toLowerCase()) {
14
+ case "real=true":
15
+ (core.storage.globalData as any).realEnv = true;
16
+ break;
17
+ case "real":
18
+ if (!(core.storage.globalData as any).realEnv) {
19
+ return;
20
+ }
21
+ break;
22
+ default:
23
+ core.debug.log(`Decorator: Unknown decorator [${decorator}]`);
24
+ }
25
+ ctx.rawtext = ctx.rawtext.trim().slice(ctx.slicedArgs[0].str.length + 2).trim();
26
+ if(!ctx.rawtext.length) return
27
+ return next();
28
+ }, true);
29
+ }
@@ -0,0 +1,88 @@
1
+ import { HZEngineCore } from "../../index.js";
2
+
3
+ export function eval_module(core: HZEngineCore) {
4
+ // single line eval command
5
+ // syntax: eval <code>
6
+ core.script.use((ctx, next) => {
7
+ if (
8
+ ctx.slicedArgs[0].isQuoted ||
9
+ ctx.slicedArgs[0].str.toLowerCase() !== "eval"
10
+ ) {
11
+ return next();
12
+ }
13
+ if (ctx.slicedArgs.length === 1) {
14
+ throw `Eval Command: no code specified`;
15
+ }
16
+ if (ctx.slicedArgs.length === 2) {
17
+ core.script.evalScope(ctx.slicedArgs[1].str);
18
+ } else {
19
+ // delete "eval" prefix
20
+ core.script.evalScope(ctx.rawtext.trim().slice(4).trim());
21
+ }
22
+ });
23
+
24
+ // multi line eval statement (script ... end script)
25
+ // syntax:
26
+ // script
27
+ // <code>
28
+ // end script
29
+
30
+ // script statement start
31
+ core.script.use((ctx, next) => {
32
+ if (ctx.rawtext.trim().split(" ")[0] !== "script") {
33
+ return next();
34
+ }
35
+ let data = ctx.startStatement("script") as unknown as ScriptStatementData;
36
+ core.script.evalScope(data.js_code_scope);
37
+ core.script.jump(data.end_position[0], data.end_position[1]);
38
+ });
39
+
40
+ // script statement end
41
+ core.script.use((ctx, next) => {
42
+ if (ctx.rawtext.trim().split(/ +/).join(" ") !== "end script")
43
+ return next();
44
+ ctx.endStatement("script");
45
+ });
46
+
47
+ // analyze script statement start
48
+ core.script.useAnalyseStatement((ctx, next) => {
49
+ if (ctx.rawtext.trim().split(" ")[0] !== "script") {
50
+ return next();
51
+ }
52
+ let data = ctx.startStatement("script") as unknown as ScriptStatementData;
53
+ data.start_position = [ctx.currentPath, ctx.currentLineIndex];
54
+ data.js_code_scope = "";
55
+ });
56
+
57
+ // analyze script code scope/statement end
58
+ core.script.useAnalyseStatement((ctx, next) => {
59
+ if (
60
+ ctx.statementStack.length &&
61
+ ctx.statementStack[ctx.statementStack.length - 1][0] === "script"
62
+ ) {
63
+ if (ctx.rawtext.trim().split(/ +/).join(" ") === "end script") {
64
+ // end script
65
+ let data = ctx.endStatement("script") as unknown as ScriptStatementData;
66
+ data.end_position = [ctx.currentPath, ctx.currentLineIndex];
67
+ ctx.setStatementData(data, [...data.start_position]);
68
+ } else {
69
+ // add code line to code scope
70
+ (
71
+ ctx.statementStack[
72
+ ctx.statementStack.length - 1
73
+ ][2] as unknown as ScriptStatementData
74
+ ).js_code_scope += ctx.rawtext.trim() + '\n';
75
+ }
76
+ } else return next();
77
+ }, true);
78
+ }
79
+
80
+ // eval a()
81
+ // eval"a()"
82
+ // eval "a()"
83
+
84
+ interface ScriptStatementData {
85
+ start_position: [path: string, index: number];
86
+ end_position: [path: string, index: number];
87
+ js_code_scope: string;
88
+ }
@@ -0,0 +1,317 @@
1
+ // / <reference types="@zeppos/device-types" />
2
+ // import hmUI from "@zos/ui";
3
+ import { Async, HZEngineCore, Script, TransformPlugin, UI } from "../../index.js";
4
+
5
+ export function img(core: HZEngineCore) {
6
+ let transform_plugin: TransformPlugin.InstanceType = core.plugins.get(
7
+ "transform"
8
+ ) as any;
9
+ if (!transform_plugin)
10
+ core.debug.log("[IMG Plugin] Info: Transform plugin not set up");
11
+ // show command
12
+ core.script.use((ctx, next) => {
13
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "show")
14
+ return next();
15
+ if (ctx.slicedArgs.length === 1)
16
+ throw `Show Command: incorrect amount of args`;
17
+ if (ctx.slicedArgs.length === 2)
18
+ throw `Show Command: incorrect amount of args`;
19
+ let parsedRes = parseImgCommandFields(ctx);
20
+
21
+ // update args to no fields
22
+ ctx.slicedArgs = parsedRes.leftedArgs;
23
+ let tag = ctx.slicedArgs[1].str;
24
+ let name_key = "";
25
+ for (let i = 1; i < ctx.slicedArgs.length; ++i) {
26
+ name_key += ctx.slicedArgs[i].str + " ";
27
+ }
28
+ name_key = name_key.trim().toLowerCase();
29
+ let path = core.storage.preloadedData.image.nameMap[name_key]?.[0];
30
+ if (!path)
31
+ throw `Show Command: image with name_key [${name_key}] not found `;
32
+ // let size = (hmUI as any).getImageInfo(path);
33
+ let size = core.platform.getImageInfo(path);
34
+ console.log(`IMG: path: ${path}, size: ${JSON.stringify(size)}`);
35
+
36
+ if (!size) throw `Show Command: read size of [${path}] failed`;
37
+ showAction(tag, path, size, parsedRes.strategy);
38
+ });
39
+
40
+ function showAction(
41
+ tag: string,
42
+ path: string,
43
+ size: UI.Size,
44
+ routerStrategy: UI.Router.RouteStrategy | null
45
+ ) {
46
+ const show_view_tag_prefix = "hzengine.img";
47
+ const show_view_name = "fg_img";
48
+ let prop: UI.FgImgViewProp = {
49
+ imgPath: path,
50
+ offset: {
51
+ x: 0,
52
+ y: 0,
53
+ },
54
+ size: {
55
+ width: size.width,
56
+ height: size.height,
57
+ },
58
+ };
59
+
60
+ let tag_prefixed = `${show_view_tag_prefix}.${tag}`;
61
+ let router = core.ui.getRouter(tag_prefixed);
62
+ if (!router) {
63
+ core.ui.addRouter(tag_prefixed, "fg");
64
+ router = core.ui.getRouter(tag_prefixed)!;
65
+ }
66
+ Async.nextTick(() => {
67
+ // @ts-ignore
68
+ router.replace<UI.FgImgViewProp>(
69
+ show_view_name,
70
+ prop,
71
+ routerStrategy ?? undefined
72
+ );
73
+ });
74
+ }
75
+
76
+ // hide command
77
+ core.script.use((ctx, next) => {
78
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "hide")
79
+ return next();
80
+ let parsedRes = parseImgCommandFields(ctx);
81
+ ctx.slicedArgs = parsedRes.leftedArgs;
82
+ if (ctx.slicedArgs.length !== 2) {
83
+ throw `Hide Command: incorrect amount of args`;
84
+ }
85
+ let tag = ctx.slicedArgs[1].str;
86
+
87
+ hideAction(tag, parsedRes.strategy);
88
+ });
89
+
90
+ function hideAction(
91
+ tag: string,
92
+ routerStrategy: UI.Router.RouteStrategy | null
93
+ ) {
94
+ const show_view_tag_prefix = "hzengine.img";
95
+
96
+ let tag_prefixed = `${show_view_tag_prefix}.${tag}`;
97
+ let router = core.ui.getRouter(tag_prefixed);
98
+ if (!router) {
99
+ throw `Hide Command: router with tag [${tag}] not found `;
100
+ }
101
+ Async.nextTick(() => {
102
+ router.clear(routerStrategy ?? undefined);
103
+ });
104
+ }
105
+
106
+ // scene command
107
+ core.script.use((ctx, next) => {
108
+ if (ctx.rawtext.trim().split(" ")[0].toLowerCase() !== "scene")
109
+ return next();
110
+ if (ctx.slicedArgs.length === 1)
111
+ throw `Scene Command: incorrect amount of args`;
112
+ if (ctx.slicedArgs.length === 2)
113
+ throw `Scene Command: incorrect amount of args`;
114
+ let parsedRes = parseImgCommandFields(ctx);
115
+
116
+ // update args to no fields
117
+ ctx.slicedArgs = parsedRes.leftedArgs;
118
+
119
+ let tag = ctx.slicedArgs[1].str;
120
+ let name_key = "";
121
+ for (let i = 1; i < ctx.slicedArgs.length; ++i) {
122
+ name_key += ctx.slicedArgs[i].str + " ";
123
+ }
124
+ name_key = name_key.trim().toLowerCase();
125
+ let path = core.storage.preloadedData.image.nameMap[name_key]?.[0];
126
+ if (!path)
127
+ throw `Scene Command: image with name_key [${name_key}] not found `;
128
+ // let size = (hmUI as any).getImageInfo(path);
129
+ let size = core.platform.getImageInfo(path);
130
+ if (!size) throw `Scene Command: read size of [${path}] failed`;
131
+
132
+ sceneAction(tag, path, size, parsedRes.strategy);
133
+ });
134
+
135
+ function sceneAction(
136
+ tag: string,
137
+ path: string,
138
+ size: UI.Size,
139
+ routerStrategy: UI.Router.RouteStrategy | null
140
+ ) {
141
+ const scene_view_tag_prefix = "hzengine.img";
142
+ const scene_view_name = "bg_img";
143
+ let prop: UI.BgImgViewProp = {
144
+ imgPath: path,
145
+ offset: {
146
+ x: 0,
147
+ y: 0,
148
+ },
149
+ size: {
150
+ width: size.width,
151
+ height: size.height,
152
+ },
153
+ };
154
+
155
+ let tag_prefixed = `${scene_view_tag_prefix}.${tag}`;
156
+ let router = core.ui.getRouter(tag_prefixed);
157
+ if (!router) {
158
+ core.ui.addRouter(tag_prefixed, "bg");
159
+ router = core.ui.getRouter(tag_prefixed)!;
160
+ }
161
+ if (!router.length) {
162
+ // @ts-ignore
163
+ Async.nextTick(() => {
164
+ // @ts-ignore
165
+ router.push<UI.BgImgViewProp>(
166
+ scene_view_name,
167
+ prop,
168
+ routerStrategy ?? undefined
169
+ );
170
+ });
171
+ } else {
172
+ // @ts-ignore
173
+ Async.nextTick(() => {
174
+ // @ts-ignore
175
+ router.update<UI.BgImgViewProp>(prop, routerStrategy ?? undefined);
176
+ });
177
+ }
178
+ }
179
+
180
+ // with
181
+ // at
182
+ // wait
183
+ // nowait
184
+
185
+ function parseImgCommandFields(ctx: Script.Context): ParsedImgCommandFields {
186
+ let slicedArgs: typeof ctx.slicedArgs = JSON.parse(
187
+ JSON.stringify(ctx.slicedArgs)
188
+ ); // TODO 深拷贝 性能
189
+
190
+ // TODO 注意这里的代码超级高耦合
191
+ let res: ReturnType<typeof parseImgCommandFields> = {
192
+ strategy: null,
193
+ wait: false,
194
+ leftedArgs: slicedArgs,
195
+ };
196
+
197
+ // wait/nowait
198
+ if (slicedArgs[slicedArgs.length - 1].str === "wait") {
199
+ res.wait = true;
200
+ slicedArgs.pop();
201
+ } else if (slicedArgs[slicedArgs.length - 1].str === "nowait") {
202
+ res.wait = false;
203
+ slicedArgs.pop();
204
+ }
205
+
206
+ // parse long fields
207
+ let keywords = ["with", "at"];
208
+ let inTransforms: string[] = [];
209
+ let outTransforms: string[] = [];
210
+ while (true) {
211
+ // console.log(`slicedArgs: ${JSON.stringify(slicedArgs)}`);
212
+
213
+ let keyword_index = findLastIndex(
214
+ slicedArgs,
215
+ (slicedArg) =>
216
+ !slicedArg.isQuoted &&
217
+ !slicedArg.isSquared &&
218
+ keywords.includes(slicedArg.str)
219
+ );
220
+ if (keyword_index === -1) break;
221
+ let keyword = slicedArgs[keyword_index].str;
222
+ let currentFieldArgs = slicedArgs.splice(
223
+ keyword_index,
224
+ slicedArgs.length - keyword_index
225
+ );
226
+ currentFieldArgs.shift();
227
+
228
+ if (keyword === "at") {
229
+ inTransforms.push(
230
+ ...Script.Utils.splitCommas(
231
+ Script.Utils.joinSlicedArgs(currentFieldArgs)
232
+ )
233
+ );
234
+ } else if (keyword === "with") {
235
+ let args = Script.Utils.parseHzsArgs(
236
+ Script.Utils.joinSlicedArgs(currentFieldArgs)
237
+ );
238
+ // console.log(`with args: ${JSON.stringify(args)}`);
239
+
240
+ for (let i = 0; i < args.length; i++) {
241
+ if (Array.isArray(args[i])) {
242
+ // Annoymous Transition Tuple
243
+ if (args[i].length > 2)
244
+ throw `Invalid Annoymous Transition Tuple: ${JSON.stringify(
245
+ args[i]
246
+ )}`;
247
+ console.log(
248
+ `Annoymous Transition Tuple: ${JSON.stringify(args[i])}`
249
+ );
250
+
251
+ if (args[i].length >= 1) {
252
+ if (Array.isArray(args[i][0])) {
253
+ outTransforms.push(...(args[i][0] as string[]));
254
+ } else {
255
+ outTransforms.push(args[i][0] as string);
256
+ }
257
+ }
258
+
259
+ if (args[i].length >= 2) {
260
+ if (Array.isArray(args[i][1])) {
261
+ inTransforms.push(...(args[i][1] as string[]));
262
+ } else {
263
+ inTransforms.push(args[i][1] as string);
264
+ }
265
+ }
266
+ } else {
267
+ // Named Transition
268
+ let transition = transform_plugin.getTransition(args[i] as string);
269
+ if (!transition) {
270
+ core.debug.log(`Transition ${args[i]} not found`);
271
+ continue;
272
+ } else {
273
+ core.debug.log(
274
+ `Transition ${args[i]} = ${JSON.stringify(transition)}`
275
+ );
276
+ inTransforms.push(...transition.inTransforms);
277
+ outTransforms.push(...transition.outTransforms);
278
+ }
279
+ }
280
+ }
281
+ }
282
+ }
283
+ // let withField: WithField = {
284
+ // outTransform: ctx.slicedArgs[withIndex + 1]?.str ?? null,
285
+ // inTransform: ctx.slicedArgs[withIndex + 2]?.str ?? null,
286
+ // };
287
+ res.strategy = transform_plugin.createStrategy(
288
+ outTransforms.length ? outTransforms : null,
289
+ inTransforms.length ? inTransforms : null
290
+ );
291
+ return res;
292
+ }
293
+
294
+ function findLastIndex<T>(array: T[], predicator: (value: T) => boolean) {
295
+ for (let i = array.length - 1; i >= 0; i--) {
296
+ if (predicator(array[i])) {
297
+ return i;
298
+ }
299
+ }
300
+ return -1;
301
+ }
302
+ const slicedArgsToTransforms = (slicedArgs: Script.Context.SlicedArg[]) =>
303
+ Script.Utils.joinSlicedArgs(slicedArgs)
304
+ .split(",")
305
+ .map((str) => str.trim())
306
+ .filter((str) => str.length > 0);
307
+
308
+ type ParsedImgCommandFields = {
309
+ strategy: UI.Router.RouteStrategy | null;
310
+ wait: boolean;
311
+ leftedArgs: Script.Context.SlicedArg[];
312
+ };
313
+ // type WithField = {
314
+ // inTransform: string | null;
315
+ // outTransform: string | null;
316
+ // };
317
+ }
@@ -0,0 +1,24 @@
1
+ import { HZEngineCore, UI } from "../../index.js";
2
+ import { $_command } from "./$.js";
3
+ import { audio_command } from "./audio.js";
4
+ import { basic_commands } from "./basic.js";
5
+ import { character_command } from "./character.js";
6
+ import { conditional } from "./conditional.js";
7
+ import { config_command } from "./config.js";
8
+ import { decorator_module } from "./decorator.js";
9
+ import { eval_module } from "./eval.js";
10
+ import { img } from "./img.js";
11
+ import { menu_statement } from "./menu.js";
12
+
13
+ export function basic_command(core: HZEngineCore) {
14
+ basic_commands(core);
15
+ character_command(core);
16
+ menu_statement(core);
17
+ decorator_module(core);
18
+ $_command(core);
19
+ eval_module(core);
20
+ conditional(core);
21
+ img(core);
22
+ audio_command(core);
23
+ config_command(core);
24
+ }
@@ -0,0 +1,178 @@
1
+ import { HZEngineCore, UI } from "../../index.js";
2
+
3
+ export function menu_statement(core: HZEngineCore) {
4
+ // menu statement start
5
+ core.script.use((ctx, next) => {
6
+ if (ctx.rawtext.trim().split(" ")[0] !== "menu") return next();
7
+ let menu_data = ctx.startStatement("menu") as unknown as MenuStatementData;
8
+
9
+ // Block the game
10
+ core.system.block();
11
+
12
+ let router = core.ui.getRouter("menu");
13
+
14
+ if (!router) {
15
+ core.ui.addRouter("menu", "ct");
16
+ router = core.ui.getRouter("menu")!;
17
+ }
18
+
19
+ let menu_view_prop = buildMenuViewProp(menu_data);
20
+ if (!router.length) {
21
+ router.push("menu", menu_view_prop);
22
+ } else {
23
+ router.update(menu_view_prop);
24
+ }
25
+ // the view contains many buttons, when the button is clicked,
26
+ // it will call core.script.jump() to jump to the next line of the @label statement
27
+ // then hide the menu
28
+ // so the script will continue to execute the next line of the @label statement
29
+ // when a @label is appended again, it represents the command between the @label and the next @label
30
+ // is executed completely, so jump to the next line of "end menu"
31
+ });
32
+
33
+ // menu statement close
34
+ core.script.use((ctx, next) => {
35
+ if (ctx.rawtext.trim().split(/ +/).join(" ") !== "end menu") return next();
36
+
37
+ ctx.endStatement("menu");
38
+ });
39
+
40
+ // menu internal label (start with @)
41
+ // syntax: @"{label_name}" [enable={js_expression}]
42
+ core.script.use((ctx, next) => {
43
+ if (!ctx.rawtext.trim().split(" ")[0].startsWith("@")) return next();
44
+ let label_name = ctx.slicedArgs[1].str;
45
+ if (
46
+ ctx.statementStack.length === 0 ||
47
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "menu"
48
+ ) {
49
+ throw `@${label_name} must in menu statement`;
50
+ }
51
+ let menu_item = ctx.statementStack[ctx.statementStack.length - 1];
52
+
53
+ let menu_data = menu_item[2] as unknown as MenuStatementData;
54
+
55
+ for (let i = 0; i < menu_data.item_list.length; i++) {
56
+ if (
57
+ menu_data.item_list[i].position[0] === ctx.currentPath &&
58
+ menu_data.item_list[i].position[1] === ctx.currentLineIndex
59
+ ) {
60
+ // the label belongs to this menu statement
61
+ // so jump to the "end menu" statement
62
+ // the script will continue from the "end menu" statement
63
+
64
+ // get the end menu statement position
65
+ let end_menu_position: [path: string, index: number] = [
66
+ ...menu_data.end_position,
67
+ ];
68
+
69
+ // jump to "end menu"
70
+ core.script.jump(end_menu_position[0], end_menu_position[1]);
71
+ return;
72
+ }
73
+ }
74
+
75
+ // the label does not belong to this menu statement, so throw error
76
+ throw `@${label_name} does not belong to closest menu statement, at file [${
77
+ ctx.currentPath
78
+ }] line [${ctx.currentLineIndex + 1}], but belong to [${
79
+ menu_item[1][0]
80
+ }] line [${menu_item[1][1] + 1}]`;
81
+ });
82
+
83
+ // analyse menu start statement
84
+ core.script.useAnalyseStatement((ctx, next) => {
85
+ if (ctx.rawtext.trim().split(" ")[0] !== "menu") return next();
86
+ let data = ctx.startStatement("menu");
87
+
88
+ // console.log("[HZEngine] Menu start");
89
+
90
+ // the data here is {} at first, so dont read its properties, because the properties are not defined yet
91
+ // we will define the properties here
92
+ (data as unknown as MenuStatementData).start_position = [
93
+ ctx.currentPath,
94
+ ctx.currentLineIndex,
95
+ ];
96
+ (data as unknown as MenuStatementData).item_list = [];
97
+ });
98
+
99
+ // analyse menu label (start with @)
100
+ core.script.useAnalyseStatement((ctx, next) => {
101
+ if (!ctx.rawtext.trim().split(" ")[0].startsWith("@")) return next();
102
+ if (
103
+ ctx.statementStack.length === 0 ||
104
+ ctx.statementStack[ctx.statementStack.length - 1][0] !== "menu"
105
+ ) {
106
+ throw `@${ctx.slicedArgs[1]} must in menu statement`;
107
+ }
108
+
109
+ // console.log("[HZEngine] Menu label: " + ctx.slicedArgs[1].str);
110
+
111
+ let menu_stack_item = ctx.statementStack[ctx.statementStack.length - 1];
112
+
113
+ // parse the enable js expression (syntax: enable={js_expression})
114
+ // get the js_expression and put it in the menu data
115
+ let enable_js_expression: string | undefined = undefined;
116
+ if (ctx.slicedArgs.length > 2) {
117
+ enable_js_expression = ctx.slicedArgs[2].str!;
118
+
119
+ if (!enable_js_expression.startsWith("enable=")) {
120
+ throw `enable js expression must start with "enable="`;
121
+ }
122
+ enable_js_expression = enable_js_expression.slice(7);
123
+ if (
124
+ enable_js_expression.startsWith("{") &&
125
+ enable_js_expression.endsWith("}")
126
+ ) {
127
+ enable_js_expression = enable_js_expression.slice(1, -1);
128
+ } else {
129
+ enable_js_expression = enable_js_expression.trim();
130
+ }
131
+
132
+ if (enable_js_expression.length > 0) {
133
+ enable_js_expression = `(${enable_js_expression})`;
134
+ } else {
135
+ throw `enable js expression must not be empty`;
136
+ }
137
+ }
138
+
139
+ (menu_stack_item[2] as unknown as MenuStatementData).item_list.push({
140
+ text: ctx.slicedArgs[1].str,
141
+ position: [ctx.currentPath, ctx.currentLineIndex],
142
+ enable_js_expression,
143
+ });
144
+ });
145
+
146
+ // analyse menu end statement
147
+ core.script.useAnalyseStatement((ctx, next) => {
148
+ if (ctx.rawtext.trim().split(/ +/).join(" ") !== "end menu") return next();
149
+ // console.log("[HZEngine] Menu analyse end");
150
+
151
+ let data: MenuStatementData = ctx.endStatement(
152
+ "menu"
153
+ ) as unknown as MenuStatementData;
154
+ // the data here is {} at first, so dont read its properties, because the properties are not defined yet
155
+ // we will define the properties here
156
+ data.end_position = [ctx.currentPath, ctx.currentLineIndex];
157
+ // set and save the menu data
158
+ ctx.setStatementData(data, [
159
+ data.start_position[0],
160
+ data.start_position[1],
161
+ ]);
162
+ });
163
+
164
+ function buildMenuViewProp(menu_data: MenuStatementData): UI.MenuViewProp {
165
+ // parse menu item string
166
+ let parsed_item_list: UI.MenuItemData[] = [];
167
+ for (let item of menu_data.item_list) {
168
+ parsed_item_list.push({ ...item, text: core.script.parseString(item.text) });
169
+ }
170
+ return { itemList: parsed_item_list };
171
+ }
172
+ }
173
+
174
+ interface MenuStatementData {
175
+ start_position: [path: string, index: number];
176
+ end_position: [path: string, index: number];
177
+ item_list: UI.MenuItemData[];
178
+ }
@@ -0,0 +1,29 @@
1
+ // import hmUI from "@zos/ui";
2
+ import { HZEngineCore, UI } from "../../index.js";
3
+ import { System } from "../../system/index.js";
4
+
5
+ export function global_gesture(core: HZEngineCore) {
6
+ function addTouchPad(layerInstance: UI.Layer<any>) {
7
+ // TODO touch pad
8
+ core.debug.log("[TouchPad] Not implemented");
9
+ // let touchPad = layerInstance.widgetFactory.createWidget(hmUI.widget.TEXT, {
10
+ // x: 0,
11
+ // y: 0,
12
+ // w: 600,
13
+ // h: 600,
14
+ // text: "",
15
+ // });
16
+
17
+ // touchPad.addEventListener(hmUI.event.SELECT, (info: any) => {
18
+ // console.log("按下了屏幕");
19
+ // if (core.system.condition === System.Condition.Pause) {
20
+ // core.system.continue();
21
+ // }
22
+ // });
23
+ }
24
+ addTouchPad(core.ui.getLayer("ct")!);
25
+ core.on("afterAddLayer", (layerInstance: UI.Layer<any>) => {
26
+ if (layerInstance.name !== "ct") return;
27
+ addTouchPad(layerInstance);
28
+ });
29
+ }