@volter/play 0.5.213 → 0.5.214
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-node/serving.mjs +14 -3
- package/package.json +11 -11
- package/serving/std-scene.ts +19 -3
- package/src/std-game.ts +6 -3
package/dist-node/serving.mjs
CHANGED
|
@@ -480,7 +480,7 @@ function stdDevPlugin(services) {
|
|
|
480
480
|
}
|
|
481
481
|
|
|
482
482
|
// serving/std-scene.ts
|
|
483
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
483
|
+
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2 } from "node:fs";
|
|
484
484
|
import { dirname as dirname3, join as join3, relative, sep } from "node:path";
|
|
485
485
|
import { fileURLToPath } from "node:url";
|
|
486
486
|
|
|
@@ -589,6 +589,15 @@ function codeSceneModule(root, file, read) {
|
|
|
589
589
|
""
|
|
590
590
|
].join("\n");
|
|
591
591
|
}
|
|
592
|
+
function levelModules(root) {
|
|
593
|
+
let found;
|
|
594
|
+
try {
|
|
595
|
+
found = readdirSync(join3(root, "levels"), { recursive: true, encoding: "utf8" });
|
|
596
|
+
} catch {
|
|
597
|
+
return [];
|
|
598
|
+
}
|
|
599
|
+
return found.filter((file) => /\.tsx?$/.test(file) && !file.split(sep).some((segment) => segment.startsWith(".") || segment === "node_modules")).map((file) => `levels/${file.split(sep).join("/")}`).sort();
|
|
600
|
+
}
|
|
592
601
|
function gameFile(root, file) {
|
|
593
602
|
if (file === null) return false;
|
|
594
603
|
const at = relative(root, file);
|
|
@@ -619,12 +628,14 @@ function stdScenePlugin(services) {
|
|
|
619
628
|
enforce: "pre",
|
|
620
629
|
// (a std game's level documents and its levels' modules prebundled as the session starts: found on the view's first open,
|
|
621
630
|
// Vite would optimize them again then, and the editor's page, which does not reload for it, would hold two copies of
|
|
622
|
-
// React. The levels' files are crawled, and the runtime's own packages are included where the game has them
|
|
631
|
+
// React. The levels' files are crawled, and the runtime's own packages are included where the game has them. The
|
|
632
|
+
// files are listed, never a pattern: one entry that is a pattern makes Vite glob the session's whole list, which
|
|
633
|
+
// skips every `node_modules`, and so every installed package's crawl entry, `globEntries` in its dependency scan)
|
|
623
634
|
config() {
|
|
624
635
|
const root = stdGame2();
|
|
625
636
|
if (root === null) return void 0;
|
|
626
637
|
const include = RUNTIME_PACKAGES.filter((name) => installedFolder(root, name) !== null);
|
|
627
|
-
return { optimizeDeps: { entries:
|
|
638
|
+
return { optimizeDeps: { entries: levelModules(root), include } };
|
|
628
639
|
},
|
|
629
640
|
async resolveId(source, importer) {
|
|
630
641
|
const ours = importer?.startsWith(VIRTUAL) === true || importer === RUNTIME_ID;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/play",
|
|
3
3
|
"publisher": "volter",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.214",
|
|
5
5
|
"engines": {
|
|
6
6
|
"vscode": "^1.104.0"
|
|
7
7
|
},
|
|
@@ -261,16 +261,16 @@
|
|
|
261
261
|
"react": "^19.0.0",
|
|
262
262
|
"react-dom": "^19.0.0",
|
|
263
263
|
"three": ">=0.186.0 <0.187.0",
|
|
264
|
-
"@volter/sdk": "0.5.
|
|
265
|
-
"@volter/project": "0.5.
|
|
264
|
+
"@volter/sdk": "0.5.214",
|
|
265
|
+
"@volter/project": "0.5.214",
|
|
266
266
|
"vite": "^6.4.3 || ^7.0.0 || ^8.0.0",
|
|
267
|
-
"@volter/live": "0.5.
|
|
268
|
-
"@volter/editor-blender": "0.1.
|
|
269
|
-
"@volter/editor-threejs": "0.5.
|
|
267
|
+
"@volter/live": "0.5.214",
|
|
268
|
+
"@volter/editor-blender": "0.1.153",
|
|
269
|
+
"@volter/editor-threejs": "0.5.214",
|
|
270
270
|
"@react-three/fiber": "^9.8.2",
|
|
271
271
|
"@react-three/rapier": "^2.2.0",
|
|
272
272
|
"postprocessing": "^6.39.5",
|
|
273
|
-
"@volter-ai/std": "^0.8.0"
|
|
273
|
+
"@volter-ai/std": "^0.8.0-0"
|
|
274
274
|
},
|
|
275
275
|
"scripts": {
|
|
276
276
|
"typecheck": "tsc -p tsconfig.json",
|
|
@@ -281,10 +281,10 @@
|
|
|
281
281
|
"access": "public"
|
|
282
282
|
},
|
|
283
283
|
"devDependencies": {
|
|
284
|
-
"@volter/editor-blender": "0.1.
|
|
285
|
-
"@volter/editor-threejs": "0.5.
|
|
286
|
-
"@volter/live": "0.5.
|
|
287
|
-
"@volter/sdk": "0.5.
|
|
284
|
+
"@volter/editor-blender": "0.1.153",
|
|
285
|
+
"@volter/editor-threejs": "0.5.214",
|
|
286
|
+
"@volter/live": "0.5.214",
|
|
287
|
+
"@volter/sdk": "0.5.214",
|
|
288
288
|
"esbuild": "0.25.12",
|
|
289
289
|
"typescript": "5.9.3"
|
|
290
290
|
},
|
package/serving/std-scene.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* cache. A URL the game's code passes as a plain string, and a glTF's external files, keep their URL: they show a
|
|
23
23
|
* change on a page reload (`docs/adr/std-scene-view.md`, decision 5).
|
|
24
24
|
*/
|
|
25
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
25
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
26
26
|
import { dirname, join, relative, sep } from 'node:path';
|
|
27
27
|
import { fileURLToPath } from 'node:url';
|
|
28
28
|
import { installedPackageDir } from '@volter/live/installed-package';
|
|
@@ -131,6 +131,20 @@ function codeSceneModule(root: string, file: string, read: Set<string>): string
|
|
|
131
131
|
].join('\n');
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
+
/** The game's level modules (`levels/**` TypeScript), each as its path from the game's folder. */
|
|
135
|
+
function levelModules(root: string): string[] {
|
|
136
|
+
let found: string[];
|
|
137
|
+
try {
|
|
138
|
+
found = readdirSync(join(root, 'levels'), { recursive: true, encoding: 'utf8' });
|
|
139
|
+
} catch {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
return found
|
|
143
|
+
.filter((file) => /\.tsx?$/.test(file) && !file.split(sep).some((segment) => segment.startsWith('.') || segment === 'node_modules'))
|
|
144
|
+
.map((file) => `levels/${file.split(sep).join('/')}`)
|
|
145
|
+
.sort();
|
|
146
|
+
}
|
|
147
|
+
|
|
134
148
|
/** Whether a module's file is the game's own (in its folder, not a dependency's). */
|
|
135
149
|
function gameFile(root: string, file: string | null): file is string {
|
|
136
150
|
if (file === null) return false;
|
|
@@ -168,12 +182,14 @@ export function stdScenePlugin(services: Pick<ProjectServingServices, 'currentPr
|
|
|
168
182
|
enforce: 'pre',
|
|
169
183
|
// (a std game's level documents and its levels' modules prebundled as the session starts: found on the view's first open,
|
|
170
184
|
// Vite would optimize them again then, and the editor's page, which does not reload for it, would hold two copies of
|
|
171
|
-
// React. The levels' files are crawled, and the runtime's own packages are included where the game has them
|
|
185
|
+
// React. The levels' files are crawled, and the runtime's own packages are included where the game has them. The
|
|
186
|
+
// files are listed, never a pattern: one entry that is a pattern makes Vite glob the session's whole list, which
|
|
187
|
+
// skips every `node_modules`, and so every installed package's crawl entry, `globEntries` in its dependency scan)
|
|
172
188
|
config() {
|
|
173
189
|
const root = stdGame();
|
|
174
190
|
if (root === null) return undefined;
|
|
175
191
|
const include = RUNTIME_PACKAGES.filter((name) => installedFolder(root, name) !== null);
|
|
176
|
-
return { optimizeDeps: { entries:
|
|
192
|
+
return { optimizeDeps: { entries: levelModules(root), include } };
|
|
177
193
|
},
|
|
178
194
|
async resolveId(source, importer) {
|
|
179
195
|
const ours = importer?.startsWith(VIRTUAL) === true || importer === RUNTIME_ID;
|
package/src/std-game.ts
CHANGED
|
@@ -515,9 +515,12 @@ async function clockAll(asked: StdClockAction): Promise<StdClock> {
|
|
|
515
515
|
if (!current) throw new Error('Nothing is playing; `play` starts it.');
|
|
516
516
|
const joined = current.players.filter((player) => player.device !== null);
|
|
517
517
|
if (joined.length === 0) throw new Error('No player\'s page has joined the game yet.');
|
|
518
|
-
|
|
519
|
-
//
|
|
520
|
-
|
|
518
|
+
// (an answer is its run's: one that comes after Stop or Restart ended that run is no reading of the game now, and a
|
|
519
|
+
// page that run's end disconnected refuses with std's own "no device" before it can answer)
|
|
520
|
+
const ended = (): Error => new Error('The run ended (Stop or Restart) before its players\' pages answered.');
|
|
521
|
+
const answers = await Promise.all(joined.map((player) => stdClock(player.device!, asked).then((clock) => ({ player, clock }))))
|
|
522
|
+
.catch((error: unknown) => { throw current.stopped ? ended() : error; });
|
|
523
|
+
if (current.stopped) throw ended();
|
|
521
524
|
const said = answers.find(({ player }) => player === answering(current)) ?? answers[0]!;
|
|
522
525
|
current.log.append('play', asked.action, { ...asked, ...said.clock });
|
|
523
526
|
setGameClock(said.clock);
|