@moku-labs/game 0.10.0 → 0.12.0
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/README.md +1 -0
- package/dist/app/page.d.mts +6 -3
- package/dist/app/page.mjs +5 -2
- package/dist/app/system.d.mts +39 -24
- package/dist/app/system.mjs +71 -49
- package/dist/app.d.mts +1 -1
- package/dist/app.mjs +1 -1
- package/dist/{assets-BHwTLVta.mjs → assets-DYiKxPBX.mjs} +27 -63
- package/dist/assets.mjs +1 -1
- package/dist/cli.d.mts +3 -2
- package/dist/cli.mjs +368 -52
- package/dist/{commands-C4QlqijJ.d.mts → commands-DvFr8Uwp.d.mts} +2 -2
- package/dist/control.d.mts +1 -1
- package/dist/{index-xxSxKJJW.d.mts → index-rnOYAriI.d.mts} +57 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +2 -2
- package/dist/inspect.d.mts +3 -3
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/lint.mjs +3 -1
- package/dist/{runtime-DOBYM6g4.d.mts → runtime-B276Gg0s.d.mts} +1 -1
- package/dist/{src-DSl1eNB1.mjs → src-SmT-XxVf.mjs} +78 -15
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +1 -1
- package/dist/{types-CefgYzFt.d.mts → types-Bcdo5-2w.d.mts} +1 -1
- package/dist/{types-BUwDHKXm.d.mts → types-BrTpz9oL.d.mts} +1 -1
- package/dist/{types-hQgI_wrq.d.mts → types-DLghaGEy.d.mts} +51 -9
- package/dist/{types-BM4shh8K.d.mts → types-D_2G6Q68.d.mts} +1 -1
- package/dist/visual.d.mts +9 -6
- package/dist/visual.mjs +7 -3
- package/llms.txt +9 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -167,6 +167,7 @@ The engine bin `moku-game` serves, builds and packs a game folder. A game writes
|
|
|
167
167
|
| `moku-game native doctor`, `native clean` | Checks or removes the native project |
|
|
168
168
|
| `moku-game keys [--check]` | Writes `generated/assets.ts`, the strings and `manifest.json` |
|
|
169
169
|
| `moku-game pack [--no-cache]` | Packs the assets into `dist/assets` |
|
|
170
|
+
| `moku-game visual [--update] [--only <name>] [--no-pixels]` | Runs the visual tests of `tests/visual/index.ts` against `tests/visual/baselines/`. The pixel leg runs on a Mac, on a page served for the run. Exit 1 when a checkpoint differs |
|
|
170
171
|
|
|
171
172
|
Every command takes `--root <dir>`, `--preload <path>` and `--serve-plugin <path>`.
|
|
172
173
|
|
package/dist/app/page.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions } from "../types-DLghaGEy.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/app/page.d.ts
|
|
4
4
|
/**
|
|
@@ -20,7 +20,7 @@ import { h as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions }
|
|
|
20
20
|
* // Written by moku-game dev. Do not edit.
|
|
21
21
|
* import "./dev.ts";
|
|
22
22
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
23
|
-
* import {
|
|
23
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
24
24
|
* import game from "../index.ts";
|
|
25
25
|
* import config from "../config.ts";
|
|
26
26
|
* import scenario0 from "../tests/scenarios/empty.ts";
|
|
@@ -30,7 +30,10 @@ import { h as StartedPage, r as GameConfig, t as AnyGameApp, u as PageOptions }
|
|
|
30
30
|
*
|
|
31
31
|
* await startPage(game, config, {
|
|
32
32
|
* scenarios: { "empty": scenario0, "full": scenario1 },
|
|
33
|
-
* system:
|
|
33
|
+
* system: systemShellOf({
|
|
34
|
+
* system: () => import("@moku-labs/system"),
|
|
35
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle")
|
|
36
|
+
* }),
|
|
34
37
|
* agents: [agent0],
|
|
35
38
|
* devModules: [devModule0]
|
|
36
39
|
* });
|
package/dist/app/page.mjs
CHANGED
|
@@ -322,7 +322,7 @@ async function startAgents(app, settings, options) {
|
|
|
322
322
|
* // Written by moku-game dev. Do not edit.
|
|
323
323
|
* import "./dev.ts";
|
|
324
324
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
325
|
-
* import {
|
|
325
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
326
326
|
* import game from "../index.ts";
|
|
327
327
|
* import config from "../config.ts";
|
|
328
328
|
* import scenario0 from "../tests/scenarios/empty.ts";
|
|
@@ -332,7 +332,10 @@ async function startAgents(app, settings, options) {
|
|
|
332
332
|
*
|
|
333
333
|
* await startPage(game, config, {
|
|
334
334
|
* scenarios: { "empty": scenario0, "full": scenario1 },
|
|
335
|
-
* system:
|
|
335
|
+
* system: systemShellOf({
|
|
336
|
+
* system: () => import("@moku-labs/system"),
|
|
337
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle")
|
|
338
|
+
* }),
|
|
336
339
|
* agents: [agent0],
|
|
337
340
|
* devModules: [devModule0]
|
|
338
341
|
* });
|
package/dist/app/system.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tn as PlayerStateProvider } from "../types-ZQLYXo5X.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { _ as
|
|
2
|
+
import { ct as PlatformProvider } from "../index-rnOYAriI.mjs";
|
|
3
|
+
import { _ as SystemShellFactory, g as SystemName, h as SystemModules } from "../types-DLghaGEy.mjs";
|
|
4
4
|
import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
5
5
|
|
|
6
6
|
//#region src/app/system.d.ts
|
|
@@ -11,7 +11,8 @@ import { Back, Haptics, KeepAwake, Lifecycle, Store } from "@moku-labs/system";
|
|
|
11
11
|
*
|
|
12
12
|
* @example
|
|
13
13
|
* ```ts
|
|
14
|
-
* const
|
|
14
|
+
* const modules = { system: () => import("@moku-labs/system"), haptics: () => import("@moku-labs/system/haptics") };
|
|
15
|
+
* const slice: SystemSlice = await createSystemApp(["haptics"], "moku-game", modules); // slice.haptics only
|
|
15
16
|
* ```
|
|
16
17
|
*/
|
|
17
18
|
type SystemSlice = {
|
|
@@ -36,7 +37,11 @@ type StoreSlice = Pick<Store.StoreApi, "get" | "set">;
|
|
|
36
37
|
*
|
|
37
38
|
* @example
|
|
38
39
|
* ```ts
|
|
39
|
-
* const system: SystemApp = await createSystemApp(["lifecycle", "store"], "com.mokulabs.timber"
|
|
40
|
+
* const system: SystemApp = await createSystemApp(["lifecycle", "store"], "com.mokulabs.timber", {
|
|
41
|
+
* system: () => import("@moku-labs/system"),
|
|
42
|
+
* lifecycle: () => import("@moku-labs/system/lifecycle"),
|
|
43
|
+
* store: () => import("@moku-labs/system/store")
|
|
44
|
+
* });
|
|
40
45
|
* await system.start(); // system.lifecycle and system.store answer from here on
|
|
41
46
|
* ```
|
|
42
47
|
*/
|
|
@@ -64,22 +69,28 @@ declare function fromSystem(system: SystemSlice): PlatformProvider;
|
|
|
64
69
|
/**
|
|
65
70
|
* Creates the `@moku-labs/system` app of the named plugins, in the fixed order `lifecycle`,
|
|
66
71
|
* `back`, `haptics`, `keepAwake`, `store`, each name once. The store is named after `namespace`.
|
|
67
|
-
* Each plugin is loaded by its
|
|
68
|
-
* The app is not started.
|
|
72
|
+
* Each plugin is loaded by its loader in `modules`, and only the named ones are called, so a page
|
|
73
|
+
* loads only the plugins its game names. The app is not started.
|
|
69
74
|
*
|
|
70
75
|
* @param names - The system plugins the game names, in any order.
|
|
71
76
|
* @param namespace - The store name: the native identifier, or `"moku-game"`.
|
|
77
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
72
78
|
* @returns The system app, not started.
|
|
73
|
-
* @throws {Error} When
|
|
79
|
+
* @throws {Error} When a named plugin has no loader in `modules`, or a loader rejects because
|
|
80
|
+
* `@moku-labs/system` is not installed.
|
|
74
81
|
* @example
|
|
75
82
|
* ```ts
|
|
76
83
|
* // A shell of its own: the store named after the app, and the haptics.
|
|
77
|
-
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber"
|
|
84
|
+
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber", {
|
|
85
|
+
* system: () => import("@moku-labs/system"),
|
|
86
|
+
* haptics: () => import("@moku-labs/system/haptics"),
|
|
87
|
+
* store: () => import("@moku-labs/system/store")
|
|
88
|
+
* });
|
|
78
89
|
* await system.start();
|
|
79
90
|
* await system.haptics?.selection(); // { ok: false, provider: "web", reason: "unsupported" } in iOS Safari
|
|
80
91
|
* ```
|
|
81
92
|
*/
|
|
82
|
-
declare function createSystemApp(names: readonly SystemName[], namespace: string): Promise<SystemApp>;
|
|
93
|
+
declare function createSystemApp(names: readonly SystemName[], namespace: string, modules: SystemModules): Promise<SystemApp>;
|
|
83
94
|
/**
|
|
84
95
|
* Builds the save provider over the system store: idb on the web, the Tauri store in the native
|
|
85
96
|
* app. It holds the document it loaded and applies each commit's patches to it, then queues one
|
|
@@ -102,28 +113,32 @@ declare function createSystemApp(names: readonly SystemName[], namespace: string
|
|
|
102
113
|
*/
|
|
103
114
|
declare function storeSave(store: StoreSlice, key: string, report: (problem: string) => void): PlayerStateProvider;
|
|
104
115
|
/**
|
|
105
|
-
*
|
|
106
|
-
* `config.system`
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
116
|
+
* Makes the system shell factory of a page over its loaders. The factory builds the shell from the
|
|
117
|
+
* resolved `config.ts`: the `@moku-labs/system` app of the names `config.system` lists, plus the
|
|
118
|
+
* store when `config.save` is `"store"`, in the fixed order. It hands the engine the platform
|
|
119
|
+
* provider over that app and, for a store save, the save provider. Nothing loads until the page
|
|
120
|
+
* calls the factory, and the page starts the shell before the game. The generated `main.ts`
|
|
121
|
+
* passes it to `startPage` with one loader per name, only when `config.ts` names a system plugin
|
|
122
|
+
* or the store save.
|
|
111
123
|
*
|
|
112
|
-
* @param
|
|
113
|
-
* @
|
|
114
|
-
* @returns The shell, not started.
|
|
115
|
-
* @throws {Error} When `@moku-labs/system` is not installed.
|
|
124
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
125
|
+
* @returns The factory the page calls; it throws the messages of `createSystemApp`.
|
|
116
126
|
* @example
|
|
117
127
|
* ```ts
|
|
118
|
-
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names
|
|
128
|
+
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names back.
|
|
119
129
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
120
|
-
* import {
|
|
130
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
121
131
|
* import game from "../../index.ts";
|
|
122
132
|
* import config from "../../config.ts";
|
|
123
133
|
*
|
|
124
|
-
* await startPage(game, config, {
|
|
134
|
+
* await startPage(game, config, {
|
|
135
|
+
* system: systemShellOf({
|
|
136
|
+
* system: () => import("@moku-labs/system"),
|
|
137
|
+
* back: () => import("@moku-labs/system/back")
|
|
138
|
+
* })
|
|
139
|
+
* });
|
|
125
140
|
* ```
|
|
126
141
|
*/
|
|
127
|
-
declare function
|
|
142
|
+
declare function systemShellOf(modules: SystemModules): SystemShellFactory;
|
|
128
143
|
//#endregion
|
|
129
|
-
export { StoreSlice, SystemApp, SystemSlice, createSystemApp, fromSystem, storeSave,
|
|
144
|
+
export { StoreSlice, SystemApp, type SystemModules, SystemSlice, createSystemApp, fromSystem, storeSave, systemShellOf };
|
package/dist/app/system.mjs
CHANGED
|
@@ -8,21 +8,6 @@ const systemOrder = [
|
|
|
8
8
|
"keepAwake",
|
|
9
9
|
"store"
|
|
10
10
|
];
|
|
11
|
-
/** One lazy import per capability plugin: the page loads only the plugins the game names. */
|
|
12
|
-
const capabilityLoaders = {
|
|
13
|
-
lifecycle: () => import("@moku-labs/system/lifecycle").then((module) => module.lifecyclePlugin),
|
|
14
|
-
back: () => import("@moku-labs/system/back").then((module) => module.backPlugin),
|
|
15
|
-
haptics: () => import("@moku-labs/system/haptics").then((module) => module.hapticsPlugin),
|
|
16
|
-
keepAwake: () => import("@moku-labs/system/keep-awake").then((module) => module.keepAwakePlugin)
|
|
17
|
-
};
|
|
18
|
-
/**
|
|
19
|
-
* Loads the store plugin, by its own lazy import.
|
|
20
|
-
*
|
|
21
|
-
* @returns The store plugin.
|
|
22
|
-
*/
|
|
23
|
-
function loadStore() {
|
|
24
|
-
return import("@moku-labs/system/store").then((module) => module.storePlugin);
|
|
25
|
-
}
|
|
26
11
|
/** The store namespace of a game with no native identifier. */
|
|
27
12
|
const defaultNamespace = "moku-game";
|
|
28
13
|
/** The store key of the save, inside the game's namespace. */
|
|
@@ -99,20 +84,45 @@ function fromSystem(system) {
|
|
|
99
84
|
};
|
|
100
85
|
}
|
|
101
86
|
/**
|
|
102
|
-
*
|
|
87
|
+
* Refuses a named plugin the page has no loader for, before anything loads. The generated
|
|
88
|
+
* `main.ts` writes a loader per name; a page of its own may miss one.
|
|
89
|
+
*
|
|
90
|
+
* @param names - The system plugins of the shell.
|
|
91
|
+
* @param modules - The loaders of the page.
|
|
92
|
+
* @throws {Error} When a name has no loader.
|
|
93
|
+
*/
|
|
94
|
+
function checkLoaders(names, modules) {
|
|
95
|
+
const missing = names.find((name) => modules[name] === void 0);
|
|
96
|
+
if (missing !== void 0) throw new Error(`[game] config.system names "${missing}", but main.ts has no loader for it.`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* One plugin per capability, through the loader of the page. The loaders are checked first, so
|
|
100
|
+
* each one called is there.
|
|
101
|
+
*/
|
|
102
|
+
const capabilityPlugins = {
|
|
103
|
+
lifecycle: (modules) => modules.lifecycle?.().then((module) => module.lifecyclePlugin),
|
|
104
|
+
back: (modules) => modules.back?.().then((module) => module.backPlugin),
|
|
105
|
+
haptics: (modules) => modules.haptics?.().then((module) => module.hapticsPlugin),
|
|
106
|
+
keepAwake: (modules) => modules.keepAwake?.().then((module) => module.keepAwakePlugin)
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Loads `@moku-labs/system` and the plugins of the names, all at once, with the loaders of the
|
|
110
|
+
* page.
|
|
103
111
|
*
|
|
104
112
|
* @param names - The system plugins, in the fixed order.
|
|
113
|
+
* @param modules - The loaders of the page.
|
|
105
114
|
* @returns The `createApp` of the package, the capability plugins in the order of the names, and
|
|
106
115
|
* the store plugin when the names hold it.
|
|
107
|
-
* @throws {Error} When the package is not installed.
|
|
116
|
+
* @throws {Error} When a name has no loader, or a loader rejects: the package is not installed.
|
|
108
117
|
*/
|
|
109
|
-
async function loadSystem(names) {
|
|
118
|
+
async function loadSystem(names, modules) {
|
|
119
|
+
checkLoaders(names, modules);
|
|
110
120
|
const capabilities = names.filter((name) => name !== "store");
|
|
111
121
|
try {
|
|
112
122
|
const [system, store, ...plugins] = await Promise.all([
|
|
113
|
-
|
|
114
|
-
names.includes("store") ?
|
|
115
|
-
...capabilities.map((name) =>
|
|
123
|
+
modules.system(),
|
|
124
|
+
names.includes("store") ? modules.store?.().then((module) => module.storePlugin) : void 0,
|
|
125
|
+
...capabilities.map((name) => capabilityPlugins[name](modules))
|
|
116
126
|
]);
|
|
117
127
|
return {
|
|
118
128
|
createApp: system.createApp,
|
|
@@ -126,23 +136,29 @@ async function loadSystem(names) {
|
|
|
126
136
|
/**
|
|
127
137
|
* Creates the `@moku-labs/system` app of the named plugins, in the fixed order `lifecycle`,
|
|
128
138
|
* `back`, `haptics`, `keepAwake`, `store`, each name once. The store is named after `namespace`.
|
|
129
|
-
* Each plugin is loaded by its
|
|
130
|
-
* The app is not started.
|
|
139
|
+
* Each plugin is loaded by its loader in `modules`, and only the named ones are called, so a page
|
|
140
|
+
* loads only the plugins its game names. The app is not started.
|
|
131
141
|
*
|
|
132
142
|
* @param names - The system plugins the game names, in any order.
|
|
133
143
|
* @param namespace - The store name: the native identifier, or `"moku-game"`.
|
|
144
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
134
145
|
* @returns The system app, not started.
|
|
135
|
-
* @throws {Error} When
|
|
146
|
+
* @throws {Error} When a named plugin has no loader in `modules`, or a loader rejects because
|
|
147
|
+
* `@moku-labs/system` is not installed.
|
|
136
148
|
* @example
|
|
137
149
|
* ```ts
|
|
138
150
|
* // A shell of its own: the store named after the app, and the haptics.
|
|
139
|
-
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber"
|
|
151
|
+
* const system = await createSystemApp(["store", "haptics"], "com.mokulabs.timber", {
|
|
152
|
+
* system: () => import("@moku-labs/system"),
|
|
153
|
+
* haptics: () => import("@moku-labs/system/haptics"),
|
|
154
|
+
* store: () => import("@moku-labs/system/store")
|
|
155
|
+
* });
|
|
140
156
|
* await system.start();
|
|
141
157
|
* await system.haptics?.selection(); // { ok: false, provider: "web", reason: "unsupported" } in iOS Safari
|
|
142
158
|
* ```
|
|
143
159
|
*/
|
|
144
|
-
async function createSystemApp(names, namespace) {
|
|
145
|
-
const { createApp, capabilities, store } = await loadSystem(systemOrder.filter((name) => names.includes(name)));
|
|
160
|
+
async function createSystemApp(names, namespace, modules) {
|
|
161
|
+
const { createApp, capabilities, store } = await loadSystem(systemOrder.filter((name) => names.includes(name)), modules);
|
|
146
162
|
if (store === void 0) return createApp({ plugins: capabilities });
|
|
147
163
|
return createApp({
|
|
148
164
|
plugins: [...capabilities, store],
|
|
@@ -271,37 +287,43 @@ function storeSave(store, key, report) {
|
|
|
271
287
|
};
|
|
272
288
|
}
|
|
273
289
|
/**
|
|
274
|
-
*
|
|
275
|
-
* `config.system`
|
|
276
|
-
*
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
290
|
+
* Makes the system shell factory of a page over its loaders. The factory builds the shell from the
|
|
291
|
+
* resolved `config.ts`: the `@moku-labs/system` app of the names `config.system` lists, plus the
|
|
292
|
+
* store when `config.save` is `"store"`, in the fixed order. It hands the engine the platform
|
|
293
|
+
* provider over that app and, for a store save, the save provider. Nothing loads until the page
|
|
294
|
+
* calls the factory, and the page starts the shell before the game. The generated `main.ts`
|
|
295
|
+
* passes it to `startPage` with one loader per name, only when `config.ts` names a system plugin
|
|
296
|
+
* or the store save.
|
|
280
297
|
*
|
|
281
|
-
* @param
|
|
282
|
-
* @
|
|
283
|
-
* @returns The shell, not started.
|
|
284
|
-
* @throws {Error} When `@moku-labs/system` is not installed.
|
|
298
|
+
* @param modules - The loaders of the page: the package, and one per named plugin.
|
|
299
|
+
* @returns The factory the page calls; it throws the messages of `createSystemApp`.
|
|
285
300
|
* @example
|
|
286
301
|
* ```ts
|
|
287
|
-
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names
|
|
302
|
+
* // The in-memory .moku/build/main.ts of moku-game build, for a game whose config.ts names back.
|
|
288
303
|
* import { startPage } from "@moku-labs/game/app/page";
|
|
289
|
-
* import {
|
|
304
|
+
* import { systemShellOf } from "@moku-labs/game/app/system";
|
|
290
305
|
* import game from "../../index.ts";
|
|
291
306
|
* import config from "../../config.ts";
|
|
292
307
|
*
|
|
293
|
-
* await startPage(game, config, {
|
|
308
|
+
* await startPage(game, config, {
|
|
309
|
+
* system: systemShellOf({
|
|
310
|
+
* system: () => import("@moku-labs/system"),
|
|
311
|
+
* back: () => import("@moku-labs/system/back")
|
|
312
|
+
* })
|
|
313
|
+
* });
|
|
294
314
|
* ```
|
|
295
315
|
*/
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
316
|
+
function systemShellOf(modules) {
|
|
317
|
+
return async (config, report) => {
|
|
318
|
+
const app = await createSystemApp(config.save === "store" ? [...config.system, "store"] : config.system, config.native?.identifier ?? defaultNamespace, modules);
|
|
319
|
+
return {
|
|
320
|
+
handle: app,
|
|
321
|
+
platform: fromSystem(app),
|
|
322
|
+
save: app.store === void 0 ? void 0 : storeSave(app.store, saveKey, report),
|
|
323
|
+
start: () => app.start(),
|
|
324
|
+
stop: () => app.stop()
|
|
325
|
+
};
|
|
304
326
|
};
|
|
305
327
|
}
|
|
306
328
|
//#endregion
|
|
307
|
-
export { createSystemApp, fromSystem, storeSave,
|
|
329
|
+
export { createSystemApp, fromSystem, storeSave, systemShellOf };
|
package/dist/app.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Xt as Json } from "./types-ZQLYXo5X.mjs";
|
|
2
|
-
import { a as GameHandle, c as MemoryProvider,
|
|
2
|
+
import { a as GameHandle, c as MemoryProvider, d as SaveKind, f as Scenario, g as SystemName, i as GameDefinition, l as PageAgent, n as GameApp, o as GamePluginConfigs, p as ScreenSeams, r as GameConfig, s as HeadlessSeams } from "./types-DLghaGEy.mjs";
|
|
3
3
|
import { AnyPluginInstance } from "@moku-labs/core";
|
|
4
4
|
|
|
5
5
|
//#region src/app/define.d.ts
|
package/dist/app.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ct as effectsPlugin, H as platformPlugin, Nt as audioPlugin, i as screen, t as createApp } from "./src-SmT-XxVf.mjs";
|
|
2
2
|
import { t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { t as fakeClock } from "./fake-MpzwZhIZ.mjs";
|
|
4
4
|
//#region src/app/define.ts
|
|
@@ -1059,21 +1059,30 @@ function copyLoose(bundle, file, bytes) {
|
|
|
1059
1059
|
const LOOSE_SIDE = 512;
|
|
1060
1060
|
/** The last segment of a key that names a particle texture starts with this. */
|
|
1061
1061
|
const FX_PREFIX = "fx-";
|
|
1062
|
+
/** A folder of particle textures: every texture below it is one. */
|
|
1063
|
+
const FX_FOLDER = "fx";
|
|
1062
1064
|
/** The groups in the order a bundle packs them. */
|
|
1063
1065
|
const GROUP_ORDER = ["fx", "main"];
|
|
1064
1066
|
/**
|
|
1065
|
-
* Picks the atlas group of one texture. A key whose last segment starts with `fx
|
|
1066
|
-
*
|
|
1067
|
+
* Picks the atlas group of one texture. A key whose last segment starts with `fx-`, or with a
|
|
1068
|
+
* folder segment `fx` between the bundle name and the stem, goes to `fx` whatever its size: the
|
|
1069
|
+
* frames of an animation in `fx/` too. Any other texture goes to `main` when no side is above
|
|
1070
|
+
* 512 px.
|
|
1067
1071
|
*
|
|
1068
1072
|
* @param texture - The key and the size of the texture.
|
|
1069
1073
|
* @returns The group, or `undefined` when the texture stays loose by its size.
|
|
1070
1074
|
* @example
|
|
1071
1075
|
* ```ts
|
|
1072
1076
|
* groupOf({ key: "ui.fx-rays", width: 504, height: 512 }); // "fx"
|
|
1077
|
+
* groupOf({ key: "ui.fx.leaf", width: 64, height: 64 }); // "fx", from assets/fx/leaf.webp of ui
|
|
1078
|
+
* groupOf({ key: "ui.fx", width: 64, height: 64 }); // "main": a stem, no folder
|
|
1073
1079
|
* ```
|
|
1074
1080
|
*/
|
|
1075
1081
|
function groupOf(texture) {
|
|
1076
|
-
|
|
1082
|
+
const segments = texture.key.split(".");
|
|
1083
|
+
const name = segments.at(-1) ?? "";
|
|
1084
|
+
const folders = segments.slice(1, -1);
|
|
1085
|
+
if (name.startsWith(FX_PREFIX) || folders.includes(FX_FOLDER)) return "fx";
|
|
1077
1086
|
return texture.width <= LOOSE_SIDE && texture.height <= LOOSE_SIDE ? "main" : void 0;
|
|
1078
1087
|
}
|
|
1079
1088
|
/**
|
|
@@ -3080,65 +3089,23 @@ async function runCli(argv, strings, ui = createBrandConsole()) {
|
|
|
3080
3089
|
*/
|
|
3081
3090
|
/** How every generated file starts. */
|
|
3082
3091
|
const HEADER = "// generated by @moku-labs/game/assets, do not edit";
|
|
3083
|
-
/** The
|
|
3084
|
-
const
|
|
3092
|
+
/** The engine root a generated module imports its types and helpers from, quoted. */
|
|
3093
|
+
const ENGINE = "\"@moku-labs/game\"";
|
|
3085
3094
|
/** How a key with no parameters is typed, so `tr` takes it with no second argument. */
|
|
3086
3095
|
const NO_PARAMS = "Record<string, never>";
|
|
3087
3096
|
/** The name of the union a plain argument is typed by. */
|
|
3088
3097
|
const ARGUMENT = "Argument";
|
|
3089
3098
|
/**
|
|
3090
|
-
* The
|
|
3091
|
-
*
|
|
3099
|
+
* The import of the helpers the messages of a module call, by the names the message bodies use:
|
|
3100
|
+
* `messageArgument` as `argument` for a plain argument, `messageDuration` as `duration` for a
|
|
3101
|
+
* duration. None when no message calls one.
|
|
3092
3102
|
*
|
|
3093
|
-
* @
|
|
3103
|
+
* @param entries - The keys of the locale.
|
|
3104
|
+
* @returns The import line, or `undefined`.
|
|
3094
3105
|
*/
|
|
3095
|
-
function
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
"function argument(value: unknown, intl: I18n.IntlKit): I18n.Part {",
|
|
3099
|
-
" if (Array.isArray(value)) {",
|
|
3100
|
-
` return { kind: "text", text: intl.list().format(value ${CAST$1} readonly string[]) };`,
|
|
3101
|
-
" }",
|
|
3102
|
-
"",
|
|
3103
|
-
" if (typeof value === \"number\") return { kind: \"text\", text: intl.number().format(value) };",
|
|
3104
|
-
"",
|
|
3105
|
-
" if (",
|
|
3106
|
-
" typeof value === \"object\" &&",
|
|
3107
|
-
" value !== null &&",
|
|
3108
|
-
" \"type\" in value &&",
|
|
3109
|
-
" \"props\" in value &&",
|
|
3110
|
-
" \"children\" in value",
|
|
3111
|
-
" ) {",
|
|
3112
|
-
` return { kind: "element", node: value ${CAST$1} I18n.ElementNode };`,
|
|
3113
|
-
" }",
|
|
3114
|
-
"",
|
|
3115
|
-
" return { kind: \"text\", text: String(value) };",
|
|
3116
|
-
"}"
|
|
3117
|
-
].join("\n");
|
|
3118
|
-
}
|
|
3119
|
-
/**
|
|
3120
|
-
* The helper a compiled `duration` calls: milliseconds into the record `Intl.DurationFormat`
|
|
3121
|
-
* reads. The same split as `durationInput` of the plugin: whole seconds rounded up, a negative or
|
|
3122
|
-
* non-finite value as zero, hours and minutes when above zero, seconds always.
|
|
3123
|
-
*
|
|
3124
|
-
* @returns The helper as source.
|
|
3125
|
-
*/
|
|
3126
|
-
function durationHelper() {
|
|
3127
|
-
return [
|
|
3128
|
-
"/** Milliseconds as Intl.DurationFormat reads them: whole seconds rounded up, seconds always. */",
|
|
3129
|
-
"function duration(ms: number): Partial<Record<Intl.DurationFormatUnit, number>> {",
|
|
3130
|
-
" const total = Number.isFinite(ms) ? Math.max(0, Math.ceil(ms / 1000)) : 0;",
|
|
3131
|
-
" const hours = Math.floor(total / 3600);",
|
|
3132
|
-
" const minutes = Math.floor((total % 3600) / 60);",
|
|
3133
|
-
" const input: Partial<Record<Intl.DurationFormatUnit, number>> = {};",
|
|
3134
|
-
"",
|
|
3135
|
-
" if (hours > 0) input.hours = hours;",
|
|
3136
|
-
" if (minutes > 0) input.minutes = minutes;",
|
|
3137
|
-
" input.seconds = total % 60;",
|
|
3138
|
-
"",
|
|
3139
|
-
" return input;",
|
|
3140
|
-
"}"
|
|
3141
|
-
].join("\n");
|
|
3106
|
+
function helperImport(entries) {
|
|
3107
|
+
const helpers = [...entries.some((entry) => entry.compiled.usesArgument) ? ["messageArgument as argument"] : [], ...entries.some((entry) => entry.compiled.usesDuration) ? ["messageDuration as duration"] : []];
|
|
3108
|
+
return helpers.length === 0 ? void 0 : `import { ${helpers.join(", ")} } from ${ENGINE};`;
|
|
3142
3109
|
}
|
|
3143
3110
|
/**
|
|
3144
3111
|
* Compares two keys, so every list the compiler writes has one order.
|
|
@@ -3152,8 +3119,8 @@ function byName(left, right) {
|
|
|
3152
3119
|
return left < right ? -1 : 1;
|
|
3153
3120
|
}
|
|
3154
3121
|
/**
|
|
3155
|
-
* Writes `generated/strings.<locale>.ts`: one arrow per key, keys sorted,
|
|
3156
|
-
* message
|
|
3122
|
+
* Writes `generated/strings.<locale>.ts`: one arrow per key, keys sorted, and the import of each
|
|
3123
|
+
* engine helper only when a message calls it.
|
|
3157
3124
|
*
|
|
3158
3125
|
* @param entries - The keys of the locale, in any order.
|
|
3159
3126
|
* @returns The text of the module.
|
|
@@ -3166,11 +3133,8 @@ function byName(left, right) {
|
|
|
3166
3133
|
function emitLocale(entries) {
|
|
3167
3134
|
const sorted = [...entries].toSorted((left, right) => byName(left.key, right.key));
|
|
3168
3135
|
const rows = sorted.map((entry) => ` ${JSON.stringify(entry.key)}: ${entry.compiled.source}`);
|
|
3169
|
-
const
|
|
3170
|
-
|
|
3171
|
-
if (sorted.some((entry) => entry.compiled.usesDuration)) blocks.push(durationHelper());
|
|
3172
|
-
blocks.push(`export default {\n${rows.join(",\n")}\n} satisfies I18n.CompiledMessages;`);
|
|
3173
|
-
return `${blocks.join("\n\n")}\n`;
|
|
3136
|
+
const imports = [`import type { I18n } from ${ENGINE};`, helperImport(sorted)].filter((line) => line !== void 0);
|
|
3137
|
+
return [`${HEADER}\n${imports.join("\n")}`, `export default {\n${rows.join(",\n")}\n} satisfies I18n.CompiledMessages;\n`].join("\n\n");
|
|
3174
3138
|
}
|
|
3175
3139
|
/**
|
|
3176
3140
|
* Writes the type of one parameter.
|
|
@@ -3230,7 +3194,7 @@ function paramsOf(params) {
|
|
|
3230
3194
|
function emitTypes(entries) {
|
|
3231
3195
|
const sorted = [...entries].toSorted((left, right) => byName(left.key, right.key));
|
|
3232
3196
|
const rows = sorted.map((entry) => ` ${JSON.stringify(entry.key)}: ${paramsOf(entry.params)};`);
|
|
3233
|
-
const blocks = sorted.some((entry) => Object.values(entry.params).some((entry) => entry.kind === "argument")) ? [`${HEADER}\nimport type { DescriptionNode } from
|
|
3197
|
+
const blocks = sorted.some((entry) => Object.values(entry.params).some((entry) => entry.kind === "argument")) ? [`${HEADER}\nimport type { DescriptionNode } from ${ENGINE};`, `type ${ARGUMENT} = string | number | readonly string[] | DescriptionNode;`] : [HEADER];
|
|
3234
3198
|
blocks.push(`export type Strings = {\n${rows.join("\n")}\n};`, "export type StringKey = keyof Strings;");
|
|
3235
3199
|
return `${blocks.join("\n\n")}\n`;
|
|
3236
3200
|
}
|
package/dist/assets.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-
|
|
1
|
+
import { a as runCli, c as emitKeys, i as compileStrings, l as emitManifest, n as importStrings, o as scanAssets, r as checkStrings, s as packAssets, t as exportStrings } from "./assets-DYiKxPBX.mjs";
|
|
2
2
|
export { checkStrings, compileStrings, emitKeys, emitManifest, exportStrings, importStrings, packAssets, runCli, scanAssets };
|
package/dist/cli.d.mts
CHANGED
|
@@ -33,8 +33,8 @@ type PreparedPage = {
|
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
35
|
* Runs one `moku-game` command line in this process: `dev`, `build`, `native <verb>`, `keys`,
|
|
36
|
-
* `pack` or `help`, with `--root`, `--preload` and `--serve-plugin` before or after the
|
|
37
|
-
* word. Every line goes through the branded console; nothing exits the process.
|
|
36
|
+
* `pack`, `visual` or `help`, with `--root`, `--preload` and `--serve-plugin` before or after the
|
|
37
|
+
* command word. Every line goes through the branded console; nothing exits the process.
|
|
38
38
|
*
|
|
39
39
|
* @param argv - The arguments after the bin.
|
|
40
40
|
* @returns The exit code.
|
|
@@ -42,6 +42,7 @@ type PreparedPage = {
|
|
|
42
42
|
* ```ts
|
|
43
43
|
* // bin/moku-game.mjs in a game folder:
|
|
44
44
|
* await runCli(["dev", "--port", "0"]); // 0 after Ctrl+C; stdout had "http://localhost:<port>/"
|
|
45
|
+
* await runCli(["visual", "--no-pixels"]); // 0 when every checkpoint of tests/visual/index.ts is the same
|
|
45
46
|
* await runCli(["help"]); // 0
|
|
46
47
|
* ```
|
|
47
48
|
*/
|