@khorsheed/dsh-game 0.1.0 → 0.1.1
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/CHANGELOG.md +8 -0
- package/lib/client.js +637 -295
- package/lib/index.js +144 -1
- package/lib/typert.host.js +142 -35
- package/lib/typert.remote-client.d.ts +4 -1
- package/lib/typert.remote-client.js +81 -25
- package/lib/types/agent.js +2 -1
- package/lib/types/client/DesignView.js +3 -3
- package/lib/types/client/ElementsView.js +13 -5
- package/lib/types/client/GameTab.js +11 -6
- package/lib/types/client/PlayView.js +3 -1
- package/lib/types/client/Preview3D.d.ts +3 -1
- package/lib/types/client/Preview3D.js +4 -2
- package/lib/types/client/ProjectSwitcher.js +2 -2
- package/lib/types/client/contract.d.ts +7 -1
- package/lib/types/client/index.js +34 -0
- package/lib/types/client/locales.d.ts +3 -0
- package/lib/types/client/locales.js +6 -0
- package/lib/types/client/preview-entry.d.ts +1 -1
- package/lib/types/client/preview-entry.js +4 -1
- package/lib/types/client/reveal.d.ts +43 -0
- package/lib/types/client/reveal.js +73 -0
- package/lib/types/project.d.ts +6 -0
- package/lib/types/project.js +10 -0
- package/lib/types/remote.d.ts +3 -1
- package/lib/types/remote.js +7 -0
- package/lib/types/skills.js +1 -0
- package/lib/types/store.d.ts +22 -1
- package/lib/types/store.js +99 -1
- package/lib/types/tools.js +15 -7
- package/lib/types/types.d.ts +26 -0
- package/lib/types/vfs.d.ts +2 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -388,6 +388,7 @@ let GameRemoteService = (() => {
|
|
|
388
388
|
let _classSuper = TypertRemoteService;
|
|
389
389
|
let _instanceExtraInitializers = [];
|
|
390
390
|
let _state_decorators;
|
|
391
|
+
let _liveVersion_decorators;
|
|
391
392
|
let _turnReport_decorators;
|
|
392
393
|
let _projectCards_decorators;
|
|
393
394
|
let _deleteProject_decorators;
|
|
@@ -417,6 +418,7 @@ let GameRemoteService = (() => {
|
|
|
417
418
|
static {
|
|
418
419
|
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
|
|
419
420
|
_state_decorators = [Remote("state")];
|
|
421
|
+
_liveVersion_decorators = [Remote("liveVersion")];
|
|
420
422
|
_turnReport_decorators = [Remote("turnReport")];
|
|
421
423
|
_projectCards_decorators = [Remote("projectCards")];
|
|
422
424
|
_deleteProject_decorators = [Remote("deleteProject")];
|
|
@@ -453,6 +455,17 @@ let GameRemoteService = (() => {
|
|
|
453
455
|
},
|
|
454
456
|
metadata: _metadata
|
|
455
457
|
}, null, _instanceExtraInitializers);
|
|
458
|
+
__esDecorate(this, null, _liveVersion_decorators, {
|
|
459
|
+
kind: "method",
|
|
460
|
+
name: "liveVersion",
|
|
461
|
+
static: false,
|
|
462
|
+
private: false,
|
|
463
|
+
access: {
|
|
464
|
+
has: (obj) => "liveVersion" in obj,
|
|
465
|
+
get: (obj) => obj.liveVersion
|
|
466
|
+
},
|
|
467
|
+
metadata: _metadata
|
|
468
|
+
}, null, _instanceExtraInitializers);
|
|
456
469
|
__esDecorate(this, null, _turnReport_decorators, {
|
|
457
470
|
kind: "method",
|
|
458
471
|
name: "turnReport",
|
|
@@ -751,6 +764,10 @@ let GameRemoteService = (() => {
|
|
|
751
764
|
state(sessionId) {
|
|
752
765
|
return this.store.sessionState(sessionId);
|
|
753
766
|
}
|
|
767
|
+
/** The bound project's newest version (cheap; the page polls it). */
|
|
768
|
+
liveVersion(sessionId) {
|
|
769
|
+
return this.store.liveVersion(sessionId);
|
|
770
|
+
}
|
|
754
771
|
/** What one of the session's turns changed (null when nothing, or not recorded). */
|
|
755
772
|
turnReport(sessionId, request) {
|
|
756
773
|
return this.store.turnReport(sessionId, request.turn);
|
|
@@ -3067,7 +3084,13 @@ var GameService = class {
|
|
|
3067
3084
|
manifest,
|
|
3068
3085
|
...manifestText === void 0 ? { manifestError: `${MANIFEST_FILE} 不见了` } : parsed?.ok === false ? { manifestError: parsed.error } : {},
|
|
3069
3086
|
chapters,
|
|
3070
|
-
elements
|
|
3087
|
+
elements: await Promise.all(elements.map(async (e) => {
|
|
3088
|
+
const info = await stat(join(row.root, e.file)).catch(() => void 0);
|
|
3089
|
+
return info === void 0 ? e : {
|
|
3090
|
+
...e,
|
|
3091
|
+
updatedAt: info.mtimeMs
|
|
3092
|
+
};
|
|
3093
|
+
})),
|
|
3071
3094
|
elementErrors: failures,
|
|
3072
3095
|
current: await readJson(join(state, "current.json")) ?? null,
|
|
3073
3096
|
candidate: await readJson(join(state, "candidate.json")) ?? null,
|
|
@@ -3102,6 +3125,126 @@ var GameService = class {
|
|
|
3102
3125
|
};
|
|
3103
3126
|
}
|
|
3104
3127
|
/** The tab's state for one session. */
|
|
3128
|
+
/**
|
|
3129
|
+
* The bound project's newest version (the waiting candidate, else the live
|
|
3130
|
+
* one), read from two small files: the page polls it to announce a version
|
|
3131
|
+
* the moment it lands, whoever's turn cut it. Version 0 means none yet.
|
|
3132
|
+
*/
|
|
3133
|
+
async liveVersion(sessionId) {
|
|
3134
|
+
const row = await this.boundProject(sessionId);
|
|
3135
|
+
if (row === void 0) return null;
|
|
3136
|
+
const state = join(row.root, STATE_DIR);
|
|
3137
|
+
const candidate = await readJson(join(state, "candidate.json"));
|
|
3138
|
+
const record = candidate ?? await readJson(join(state, "current.json"));
|
|
3139
|
+
const show = this.shows.get(row.id);
|
|
3140
|
+
const extra = show === void 0 ? {} : { show };
|
|
3141
|
+
if (record === void 0) return {
|
|
3142
|
+
projectId: row.id,
|
|
3143
|
+
version: 0,
|
|
3144
|
+
kind: "none",
|
|
3145
|
+
at: null,
|
|
3146
|
+
...extra
|
|
3147
|
+
};
|
|
3148
|
+
return {
|
|
3149
|
+
projectId: row.id,
|
|
3150
|
+
version: record.version,
|
|
3151
|
+
kind: candidate !== void 0 ? "candidate" : "deployed",
|
|
3152
|
+
at: record.at,
|
|
3153
|
+
...record.by === void 0 ? {} : { by: record.by },
|
|
3154
|
+
...extra
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
/** The agent's latest 「请用户看这里」 per project (in memory: a request is for the moment, not history). */
|
|
3158
|
+
shows = /* @__PURE__ */ new Map();
|
|
3159
|
+
showSeq = 0;
|
|
3160
|
+
/**
|
|
3161
|
+
* After a passing `game_publish`: leave the pages showing this project a
|
|
3162
|
+
* request to take their game tab to the result. `show` is the agent's choice
|
|
3163
|
+
* (play, versions, elements, elements:<id or name>, design:<chapter>); left
|
|
3164
|
+
* out — or not found — the version decides: the one element it changed, the
|
|
3165
|
+
* grid when several, else the play area (a candidate always opens play,
|
|
3166
|
+
* where it waits for the user's OK). Pages pick it up on their poll.
|
|
3167
|
+
* @returns a line for the tool's answer.
|
|
3168
|
+
*/
|
|
3169
|
+
async showAfterPublish(sessionId, version, candidate, show, note) {
|
|
3170
|
+
const row = await this.boundProject(sessionId);
|
|
3171
|
+
const project = row === void 0 ? void 0 : await this.view(row.id);
|
|
3172
|
+
if (row === void 0 || project === void 0) return "";
|
|
3173
|
+
let target = null;
|
|
3174
|
+
let refused = "";
|
|
3175
|
+
const asked = (show ?? "").trim();
|
|
3176
|
+
if (asked !== "") {
|
|
3177
|
+
const [view, ...rest] = asked.split(":");
|
|
3178
|
+
const name = rest.join(":").trim();
|
|
3179
|
+
if (view === "play" || view === "versions" || view === "elements" && name === "") target = { view };
|
|
3180
|
+
else if (view === "elements") {
|
|
3181
|
+
const e = project.elements.find((x) => x.id === name || x.name === name);
|
|
3182
|
+
if (e !== void 0) target = {
|
|
3183
|
+
view,
|
|
3184
|
+
elementId: e.id
|
|
3185
|
+
};
|
|
3186
|
+
} else if (view === "design") {
|
|
3187
|
+
const c = project.chapters.find((x) => x.id === name || x.title === name);
|
|
3188
|
+
if (c !== void 0) target = {
|
|
3189
|
+
view,
|
|
3190
|
+
chapterId: c.id
|
|
3191
|
+
};
|
|
3192
|
+
}
|
|
3193
|
+
if (target === null) refused = `(show「${asked}」找不到,改用默认位置)`;
|
|
3194
|
+
}
|
|
3195
|
+
let changedNames = [];
|
|
3196
|
+
if (target === null) {
|
|
3197
|
+
const decided = candidate ? {
|
|
3198
|
+
target: { view: "play" },
|
|
3199
|
+
names: []
|
|
3200
|
+
} : await this.changedBy(row.root, version);
|
|
3201
|
+
target = decided.target;
|
|
3202
|
+
changedNames = decided.names;
|
|
3203
|
+
}
|
|
3204
|
+
const words = (note ?? "").trim();
|
|
3205
|
+
const text = words !== "" ? words : candidate ? `v${version} 等你确认上线` : changedNames.length > 0 ? `v${version}:改了${changedNames.slice(0, 3).join("、")}${changedNames.length > 3 ? ` 等 ${changedNames.length} 个` : ""}` : `v${version} 已上线`;
|
|
3206
|
+
this.shows.set(row.id, {
|
|
3207
|
+
seq: ++this.showSeq,
|
|
3208
|
+
target,
|
|
3209
|
+
note: text.slice(0, 120),
|
|
3210
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
3211
|
+
});
|
|
3212
|
+
this.notify(row.id);
|
|
3213
|
+
return `右栏会打开:${target.view === "play" ? "试玩" : target.view === "versions" ? "版本" : target.view === "design" ? `策划·${target.chapterId}` : target.elementId === void 0 ? "元素列表" : `元素「${target.elementId}」`}${refused}。`;
|
|
3214
|
+
}
|
|
3215
|
+
/** Where a version's change is: the one element it changed, the grid for several, else play (code, assets, a first version). */
|
|
3216
|
+
async changedBy(root, version) {
|
|
3217
|
+
const earlier = (await this.readVersions(root)).map((v) => v.version).filter((v) => v < version);
|
|
3218
|
+
const play = {
|
|
3219
|
+
target: { view: "play" },
|
|
3220
|
+
names: []
|
|
3221
|
+
};
|
|
3222
|
+
if (earlier.length === 0) return play;
|
|
3223
|
+
const prev = Math.max(...earlier);
|
|
3224
|
+
const dir = (v) => join(root, STATE_DIR, "versions", String(v));
|
|
3225
|
+
if (!await stat(dir(prev)).then(() => true, () => false)) return play;
|
|
3226
|
+
const [before, after] = await Promise.all([this.elementIndex(dir(prev)), this.elementIndex(dir(version))]);
|
|
3227
|
+
const changed = [...after].filter(([id, e]) => before.get(id)?.json !== e.json);
|
|
3228
|
+
const others = async (v) => new Map((await walk(dir(v), (p) => !p.startsWith("elements/"))).map((f) => [f.path, f.data.toString("base64")]));
|
|
3229
|
+
const [a, b] = await Promise.all([others(prev), others(version)]);
|
|
3230
|
+
const otherChanged = a.size !== b.size || [...b].some(([p, d]) => a.get(p) !== d);
|
|
3231
|
+
const names = changed.map(([, e]) => e.name);
|
|
3232
|
+
if (otherChanged || changed.length === 0) return {
|
|
3233
|
+
target: { view: "play" },
|
|
3234
|
+
names
|
|
3235
|
+
};
|
|
3236
|
+
if (changed.length === 1) return {
|
|
3237
|
+
target: {
|
|
3238
|
+
view: "elements",
|
|
3239
|
+
elementId: changed[0][0]
|
|
3240
|
+
},
|
|
3241
|
+
names
|
|
3242
|
+
};
|
|
3243
|
+
return {
|
|
3244
|
+
target: { view: "elements" },
|
|
3245
|
+
names
|
|
3246
|
+
};
|
|
3247
|
+
}
|
|
3105
3248
|
async sessionState(sessionId) {
|
|
3106
3249
|
const bound = await this.boundProject(sessionId);
|
|
3107
3250
|
return {
|