@auraindustry/aurajs 0.1.3 → 0.1.5
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 +7 -0
- package/benchmarks/perf-thresholds.json +27 -0
- package/package.json +6 -1
- package/src/ai-guidance.mjs +302 -0
- package/src/authored-project.mjs +498 -2
- package/src/build-contract/capabilities.mjs +87 -1
- package/src/build-contract/constants.mjs +1 -0
- package/src/build-contract.mjs +2 -0
- package/src/bundler.mjs +143 -13
- package/src/cli.mjs +681 -13
- package/src/commands/packs.mjs +741 -0
- package/src/commands/project-authoring.mjs +128 -1
- package/src/conformance/cases/app-and-ui-runtime-cases.mjs +1 -2
- package/src/conformance/cases/core-runtime-cases.mjs +6 -2
- package/src/conformance/cases/scene3d-and-media-cases.mjs +238 -0
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +265 -4
- package/src/conformance-mobile.mjs +166 -0
- package/src/conformance.mjs +89 -30
- package/src/evidence-bundle.mjs +242 -0
- package/src/headless-test/runtime-coordinator.mjs +186 -33
- package/src/headless-test.mjs +2 -0
- package/src/helpers/2d/index.mjs +183 -0
- package/src/helpers/index.mjs +26 -0
- package/src/helpers/starter-utils/adventure-objectives.js +102 -0
- package/src/helpers/starter-utils/adventure-world-2d.js +221 -0
- package/src/helpers/starter-utils/animation-2d.js +337 -0
- package/src/helpers/starter-utils/animation-packaging-2d.js +203 -0
- package/src/helpers/starter-utils/atlas-assets-2d.js +111 -0
- package/src/helpers/starter-utils/autoplay-debug-2d.js +215 -0
- package/src/helpers/starter-utils/avatar-3d.js +404 -0
- package/src/helpers/starter-utils/combat-feedback-2d.js +320 -0
- package/src/helpers/starter-utils/combat-runtime-2d.js +290 -0
- package/src/helpers/starter-utils/core.js +150 -0
- package/src/helpers/starter-utils/dialogue-2d.js +351 -0
- package/src/helpers/starter-utils/enemy-archetypes-2d.js +68 -0
- package/src/helpers/starter-utils/index.js +26 -0
- package/src/helpers/starter-utils/inventory-2d.js +268 -0
- package/src/helpers/starter-utils/journal-2d.js +267 -0
- package/src/helpers/starter-utils/platformer-3d.js +132 -0
- package/src/helpers/starter-utils/scene-audio-2d.js +236 -0
- package/src/helpers/starter-utils/streamed-world-2d.js +378 -0
- package/src/helpers/starter-utils/tilemap-nav-2d.js +499 -0
- package/src/helpers/starter-utils/tilemap-world-2d.js +205 -0
- package/src/helpers/starter-utils/triggers.js +662 -0
- package/src/helpers/starter-utils/tween-2d.js +615 -0
- package/src/helpers/starter-utils/wave-director.js +101 -0
- package/src/helpers/starter-utils/world-compositor-2d.js +253 -0
- package/src/helpers/starter-utils/world-persistence-2d.js +180 -0
- package/src/mobile/android/build.mjs +606 -0
- package/src/mobile/android/host-artifact.mjs +280 -0
- package/src/mobile/ios/build.mjs +1323 -0
- package/src/mobile/ios/host-artifact.mjs +819 -0
- package/src/mobile/shared/capabilities.mjs +174 -0
- package/src/packs/catalog.mjs +259 -0
- package/src/perf-benchmark-runner.mjs +17 -12
- package/src/perf-benchmark.mjs +408 -4
- package/src/publish-command.mjs +303 -6
- package/src/replay-runtime.mjs +257 -0
- package/src/scaffold/config.mjs +2 -0
- package/src/scaffold/fs.mjs +8 -1
- package/src/scaffold/project-docs.mjs +43 -1
- package/src/scaffold.mjs +4 -0
- package/src/session-runtime.mjs +4 -3
- package/src/web-conformance.mjs +0 -36
- package/templates/create/2d-adventure/config/gameplay/adventure.config.js +9 -6
- package/templates/create/2d-adventure/content/gameplay/dialogue.js +85 -0
- package/templates/create/2d-adventure/content/gameplay/world.js +32 -36
- package/templates/create/2d-adventure/content/gameplay/world.tilemap.json +273 -0
- package/templates/create/2d-adventure/docs/design/loop.md +4 -3
- package/templates/create/2d-adventure/prefabs/relic.prefab.js +10 -10
- package/templates/create/2d-adventure/prefabs/world.prefab.js +127 -74
- package/templates/create/2d-adventure/scenes/gameplay.scene.js +603 -112
- package/templates/create/2d-adventure/src/runtime/capabilities.js +16 -0
- package/templates/create/2d-adventure/ui/hud.screen.js +187 -4
- package/templates/create/2d-adventure/ui/journal.screen.js +183 -0
- package/templates/create/3d/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d/src/runtime/capabilities.js +5 -0
- package/templates/create/3d/src/runtime/materials.js +10 -0
- package/templates/create/3d-adventure/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-adventure/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-adventure/src/runtime/materials.js +11 -0
- package/templates/create/3d-collectathon/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-collectathon/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-collectathon/src/runtime/materials.js +10 -0
- package/templates/create/shared/src/runtime/ui-forms.js +552 -0
- package/templates/create/shared/src/starter-utils/adventure-world-2d.js +221 -0
- package/templates/create/shared/src/starter-utils/animation-packaging-2d.js +203 -0
- package/templates/create/shared/src/starter-utils/atlas-assets-2d.js +111 -0
- package/templates/create/shared/src/starter-utils/autoplay-debug-2d.js +215 -0
- package/templates/create/shared/src/starter-utils/combat-runtime-2d.js +290 -0
- package/templates/create/shared/src/starter-utils/dialogue-2d.js +351 -0
- package/templates/create/shared/src/starter-utils/index.js +15 -1
- package/templates/create/shared/src/starter-utils/inventory-2d.js +268 -0
- package/templates/create/shared/src/starter-utils/journal-2d.js +267 -0
- package/templates/create/shared/src/starter-utils/scene-audio-2d.js +236 -0
- package/templates/create/shared/src/starter-utils/streamed-world-2d.js +378 -0
- package/templates/create/shared/src/starter-utils/tilemap-nav-2d.js +499 -0
- package/templates/create/shared/src/starter-utils/tilemap-world-2d.js +205 -0
- package/templates/create/shared/src/starter-utils/world-compositor-2d.js +253 -0
- package/templates/create/shared/src/starter-utils/world-persistence-2d.js +180 -0
- package/templates/create-bin/play.js +36 -7
- package/templates/skills/auramaxx/SKILL.md +46 -0
- package/templates/skills/auramaxx/project-requirements.md +68 -0
- package/templates/skills/auramaxx/starter-recipes.md +104 -0
- package/templates/skills/auramaxx/validation-checklist.md +49 -0
- package/templates/skills/aurajs/SKILL.md +0 -96
- package/templates/skills/aurajs/api-contract-3d.md +0 -7
- package/templates/skills/aurajs/api-contract.md +0 -7
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
function finite(value, fallback = 0) {
|
|
2
|
+
const numeric = Number(value);
|
|
3
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
function positiveInteger(value, fallback = null) {
|
|
7
|
+
const numeric = Math.floor(finite(value, Number.NaN));
|
|
8
|
+
if (numeric >= 1) return numeric;
|
|
9
|
+
return fallback;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function normalizeText(value, fallback) {
|
|
13
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : fallback;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function resolveAura(auraRef = globalThis.aura) {
|
|
17
|
+
return auraRef && typeof auraRef === 'object' ? auraRef : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function normalizeStageIds(value) {
|
|
21
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
22
|
+
return ['scene', 'light', 'final'];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const stageIds = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
for (const entry of value) {
|
|
28
|
+
const id = normalizeText(entry, null);
|
|
29
|
+
if (!id || seen.has(id)) continue;
|
|
30
|
+
seen.add(id);
|
|
31
|
+
stageIds.push(id);
|
|
32
|
+
}
|
|
33
|
+
return stageIds.length > 0 ? stageIds : ['scene', 'light', 'final'];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createTarget(aura, width, height) {
|
|
37
|
+
if (!aura?.draw2d || typeof aura.draw2d.createRenderTarget !== 'function') return null;
|
|
38
|
+
const target = aura.draw2d.createRenderTarget(width, height);
|
|
39
|
+
return target && typeof target === 'object' && target.ok === true ? target : null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function destroyTarget(aura, target) {
|
|
43
|
+
if (!target || typeof target !== 'object' || target.ok !== true) return false;
|
|
44
|
+
if (!aura?.draw2d || typeof aura.draw2d.destroyRenderTarget !== 'function') return false;
|
|
45
|
+
aura.draw2d.destroyRenderTarget(target);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveDimensions(compositor, options = {}) {
|
|
50
|
+
const width = positiveInteger(
|
|
51
|
+
options.width ?? compositor.fixedWidth,
|
|
52
|
+
null,
|
|
53
|
+
);
|
|
54
|
+
const height = positiveInteger(
|
|
55
|
+
options.height ?? compositor.fixedHeight,
|
|
56
|
+
null,
|
|
57
|
+
);
|
|
58
|
+
if (width == null || height == null) return null;
|
|
59
|
+
return { width, height };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getStageRecord(compositor, stageId) {
|
|
63
|
+
return Array.isArray(compositor?.stages)
|
|
64
|
+
? compositor.stages.find((entry) => entry.id === stageId) || null
|
|
65
|
+
: null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeStageDefinitions(compositor, stageDefinitions) {
|
|
69
|
+
if (Array.isArray(stageDefinitions)) {
|
|
70
|
+
return compositor.stageIds.map((stageId) => (
|
|
71
|
+
stageDefinitions.find((entry) => entry?.id === stageId) || { id: stageId }
|
|
72
|
+
));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (stageDefinitions && typeof stageDefinitions === 'object') {
|
|
76
|
+
return compositor.stageIds.map((stageId) => {
|
|
77
|
+
const entry = stageDefinitions[stageId];
|
|
78
|
+
if (typeof entry === 'function') {
|
|
79
|
+
return { id: stageId, draw: entry };
|
|
80
|
+
}
|
|
81
|
+
if (entry && typeof entry === 'object') {
|
|
82
|
+
return { id: stageId, ...entry };
|
|
83
|
+
}
|
|
84
|
+
return { id: stageId };
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return compositor.stageIds.map((stageId) => ({ id: stageId }));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function createWorldCompositor2D(options = {}) {
|
|
92
|
+
const stageIds = normalizeStageIds(options.stageIds);
|
|
93
|
+
const finalStageId = stageIds.includes(options.finalStageId)
|
|
94
|
+
? options.finalStageId
|
|
95
|
+
: stageIds[stageIds.length - 1];
|
|
96
|
+
return {
|
|
97
|
+
graphName: normalizeText(options.graphName, 'world-compositor-2d'),
|
|
98
|
+
stageIds,
|
|
99
|
+
finalStageId,
|
|
100
|
+
fixedWidth: positiveInteger(options.width ?? options.fixedWidth, null),
|
|
101
|
+
fixedHeight: positiveInteger(options.height ?? options.fixedHeight, null),
|
|
102
|
+
width: 0,
|
|
103
|
+
height: 0,
|
|
104
|
+
targets: null,
|
|
105
|
+
stages: null,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function destroyWorldCompositor2D(compositor, auraRef = globalThis.aura) {
|
|
110
|
+
const aura = resolveAura(auraRef);
|
|
111
|
+
if (!compositor || typeof compositor !== 'object') return false;
|
|
112
|
+
if (compositor.targets && typeof compositor.targets === 'object') {
|
|
113
|
+
for (const stageId of compositor.stageIds || []) {
|
|
114
|
+
destroyTarget(aura, compositor.targets[stageId]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
compositor.width = 0;
|
|
118
|
+
compositor.height = 0;
|
|
119
|
+
compositor.targets = null;
|
|
120
|
+
compositor.stages = null;
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function ensureWorldCompositorTargets2D(compositor, options = {}, auraRef = globalThis.aura) {
|
|
125
|
+
const aura = resolveAura(auraRef);
|
|
126
|
+
if (!compositor || typeof compositor !== 'object') {
|
|
127
|
+
throw new Error('world compositor state is required.');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const dimensions = resolveDimensions(compositor, options);
|
|
131
|
+
if (!dimensions) return null;
|
|
132
|
+
if (
|
|
133
|
+
compositor.targets
|
|
134
|
+
&& compositor.width === dimensions.width
|
|
135
|
+
&& compositor.height === dimensions.height
|
|
136
|
+
) {
|
|
137
|
+
return compositor.targets;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
destroyWorldCompositor2D(compositor, aura);
|
|
141
|
+
|
|
142
|
+
const targets = {};
|
|
143
|
+
for (const stageId of compositor.stageIds) {
|
|
144
|
+
const target = createTarget(aura, dimensions.width, dimensions.height);
|
|
145
|
+
if (!target) {
|
|
146
|
+
for (const created of Object.values(targets)) {
|
|
147
|
+
destroyTarget(aura, created);
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
targets[stageId] = target;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
compositor.width = dimensions.width;
|
|
155
|
+
compositor.height = dimensions.height;
|
|
156
|
+
compositor.targets = targets;
|
|
157
|
+
return targets;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function runWorldCompositor2D(
|
|
161
|
+
compositor,
|
|
162
|
+
stageDefinitions,
|
|
163
|
+
options = {},
|
|
164
|
+
auraRef = globalThis.aura,
|
|
165
|
+
) {
|
|
166
|
+
const aura = resolveAura(auraRef);
|
|
167
|
+
if (!compositor || typeof compositor !== 'object') {
|
|
168
|
+
throw new Error('world compositor state is required.');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const dimensions = resolveDimensions(compositor, options);
|
|
172
|
+
const fallbackDraw = typeof options.fallbackDraw === 'function' ? options.fallbackDraw : null;
|
|
173
|
+
if (!dimensions) {
|
|
174
|
+
if (fallbackDraw) fallbackDraw({ reasonCode: 'invalid_world_compositor_size' });
|
|
175
|
+
return {
|
|
176
|
+
ok: false,
|
|
177
|
+
reasonCode: 'invalid_world_compositor_size',
|
|
178
|
+
graph: null,
|
|
179
|
+
targets: null,
|
|
180
|
+
finalStage: null,
|
|
181
|
+
width: 0,
|
|
182
|
+
height: 0,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const targets = ensureWorldCompositorTargets2D(compositor, dimensions, aura);
|
|
187
|
+
if (!targets) {
|
|
188
|
+
if (fallbackDraw) fallbackDraw({ reasonCode: 'draw2d_render_target_unavailable' });
|
|
189
|
+
return {
|
|
190
|
+
ok: false,
|
|
191
|
+
reasonCode: 'draw2d_render_target_unavailable',
|
|
192
|
+
graph: null,
|
|
193
|
+
targets: null,
|
|
194
|
+
finalStage: null,
|
|
195
|
+
width: dimensions.width,
|
|
196
|
+
height: dimensions.height,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const definitions = normalizeStageDefinitions(compositor, stageDefinitions);
|
|
201
|
+
compositor.stages = definitions;
|
|
202
|
+
if (!aura?.draw2d || typeof aura.draw2d.runCompositorGraph !== 'function') {
|
|
203
|
+
if (fallbackDraw) {
|
|
204
|
+
fallbackDraw({
|
|
205
|
+
reasonCode: 'draw2d_compositor_unavailable',
|
|
206
|
+
width: dimensions.width,
|
|
207
|
+
height: dimensions.height,
|
|
208
|
+
targets,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
ok: false,
|
|
213
|
+
reasonCode: 'draw2d_compositor_unavailable',
|
|
214
|
+
graph: null,
|
|
215
|
+
targets,
|
|
216
|
+
finalStage: targets[compositor.finalStageId] || null,
|
|
217
|
+
width: dimensions.width,
|
|
218
|
+
height: dimensions.height,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const graph = aura.draw2d.runCompositorGraph(
|
|
223
|
+
compositor.graphName,
|
|
224
|
+
definitions.map((entry) => ({
|
|
225
|
+
id: entry.id,
|
|
226
|
+
target: targets[entry.id],
|
|
227
|
+
draw: () => {
|
|
228
|
+
if (typeof entry.draw !== 'function') return;
|
|
229
|
+
entry.draw({
|
|
230
|
+
id: entry.id,
|
|
231
|
+
width: dimensions.width,
|
|
232
|
+
height: dimensions.height,
|
|
233
|
+
graphName: compositor.graphName,
|
|
234
|
+
targets,
|
|
235
|
+
aura,
|
|
236
|
+
stage: getStageRecord(compositor, entry.id),
|
|
237
|
+
finalStageId: compositor.finalStageId,
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
})),
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const finalStageIndex = compositor.stageIds.indexOf(compositor.finalStageId);
|
|
244
|
+
return {
|
|
245
|
+
ok: graph?.ok === true,
|
|
246
|
+
reasonCode: graph?.reasonCode || null,
|
|
247
|
+
graph,
|
|
248
|
+
targets,
|
|
249
|
+
finalStage: graph?.stages?.[finalStageIndex] || targets[compositor.finalStageId] || null,
|
|
250
|
+
width: dimensions.width,
|
|
251
|
+
height: dimensions.height,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { syncStreamedWorldFocus2D } from './streamed-world-2d.js';
|
|
2
|
+
|
|
3
|
+
function cloneSnapshot(value) {
|
|
4
|
+
if (value == null) return value;
|
|
5
|
+
return JSON.parse(JSON.stringify(value));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function resolveStorage(auraRef = globalThis.aura) {
|
|
9
|
+
const storage = auraRef?.storage;
|
|
10
|
+
if (!storage || typeof storage !== 'object') return null;
|
|
11
|
+
return storage;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function storageSave(storage, key, value) {
|
|
15
|
+
if (!storage || typeof key !== 'string' || key.length === 0) return false;
|
|
16
|
+
if (typeof storage.save === 'function') {
|
|
17
|
+
storage.save(key, value);
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (typeof storage.set === 'function') {
|
|
21
|
+
storage.set(key, value);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function storageLoad(storage, key, fallback = null) {
|
|
28
|
+
if (!storage || typeof key !== 'string' || key.length === 0) return fallback;
|
|
29
|
+
if (typeof storage.load === 'function') {
|
|
30
|
+
return storage.load(key, fallback);
|
|
31
|
+
}
|
|
32
|
+
if (typeof storage.get === 'function') {
|
|
33
|
+
return storage.get(key, fallback);
|
|
34
|
+
}
|
|
35
|
+
return fallback;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function storageDelete(storage, key) {
|
|
39
|
+
if (!storage || typeof key !== 'string' || key.length === 0) return false;
|
|
40
|
+
if (typeof storage.delete === 'function') {
|
|
41
|
+
storage.delete(key);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function normalizeSnapshot(snapshot) {
|
|
48
|
+
if (!snapshot || typeof snapshot !== 'object' || Array.isArray(snapshot)) return null;
|
|
49
|
+
return {
|
|
50
|
+
version: Number.isFinite(Number(snapshot.version)) ? Number(snapshot.version) : 1,
|
|
51
|
+
scope: typeof snapshot.scope === 'string' ? snapshot.scope : 'streamed-world-2d',
|
|
52
|
+
activeRegionId: typeof snapshot.activeRegionId === 'string' ? snapshot.activeRegionId : null,
|
|
53
|
+
focus: snapshot.focus && typeof snapshot.focus === 'object'
|
|
54
|
+
? {
|
|
55
|
+
x: Number(snapshot.focus.x) || 0,
|
|
56
|
+
y: Number(snapshot.focus.y) || 0,
|
|
57
|
+
}
|
|
58
|
+
: null,
|
|
59
|
+
world: snapshot.world == null ? null : cloneSnapshot(snapshot.world),
|
|
60
|
+
regions: Array.isArray(snapshot.regions)
|
|
61
|
+
? snapshot.regions
|
|
62
|
+
.filter((entry) => entry && typeof entry === 'object' && typeof entry.id === 'string')
|
|
63
|
+
.map((entry) => ({
|
|
64
|
+
id: entry.id,
|
|
65
|
+
data: cloneSnapshot(entry.data),
|
|
66
|
+
}))
|
|
67
|
+
: [],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function captureStreamedWorldSnapshot2D(stream, options = {}) {
|
|
72
|
+
if (!stream || !(stream.regionById instanceof Map)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const captureRegion = typeof options.captureRegion === 'function' ? options.captureRegion : null;
|
|
76
|
+
const captureWorld = typeof options.captureWorld === 'function' ? options.captureWorld : null;
|
|
77
|
+
const regionIds = Array.isArray(options.regionIds)
|
|
78
|
+
? options.regionIds.filter((entry) => typeof entry === 'string')
|
|
79
|
+
: stream.regions.map((entry) => entry.id);
|
|
80
|
+
const regions = [];
|
|
81
|
+
|
|
82
|
+
regionIds.forEach((regionId) => {
|
|
83
|
+
const descriptor = stream.regionById.get(regionId) || null;
|
|
84
|
+
if (!descriptor || !captureRegion) return;
|
|
85
|
+
const record = stream.loaded?.get(regionId) || null;
|
|
86
|
+
const data = captureRegion(descriptor, record, stream, options);
|
|
87
|
+
if (data == null) return;
|
|
88
|
+
regions.push({
|
|
89
|
+
id: regionId,
|
|
90
|
+
data: cloneSnapshot(data),
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
version: 1,
|
|
96
|
+
scope: options.scope ?? 'streamed-world-2d',
|
|
97
|
+
activeRegionId: stream.activeRegionId ?? null,
|
|
98
|
+
focus: stream.focus ? { x: Number(stream.focus.x) || 0, y: Number(stream.focus.y) || 0 } : null,
|
|
99
|
+
world: captureWorld ? cloneSnapshot(captureWorld(stream, options)) : null,
|
|
100
|
+
regions,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function applyStreamedWorldSnapshot2D(stream, snapshot, options = {}) {
|
|
105
|
+
if (!stream || !(stream.regionById instanceof Map)) {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
reasonCode: 'invalid_stream',
|
|
109
|
+
appliedRegionIds: [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const normalized = normalizeSnapshot(snapshot);
|
|
113
|
+
if (!normalized) {
|
|
114
|
+
return {
|
|
115
|
+
ok: false,
|
|
116
|
+
reasonCode: 'invalid_snapshot',
|
|
117
|
+
appliedRegionIds: [],
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const applyRegion = typeof options.applyRegion === 'function' ? options.applyRegion : null;
|
|
121
|
+
const applyWorld = typeof options.applyWorld === 'function' ? options.applyWorld : null;
|
|
122
|
+
const appliedRegionIds = [];
|
|
123
|
+
|
|
124
|
+
if (applyWorld && normalized.world != null) {
|
|
125
|
+
applyWorld(cloneSnapshot(normalized.world), stream, options);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
normalized.regions.forEach((entry) => {
|
|
129
|
+
const descriptor = stream.regionById.get(entry.id) || null;
|
|
130
|
+
if (!descriptor || !applyRegion) return;
|
|
131
|
+
const record = stream.loaded?.get(entry.id) || null;
|
|
132
|
+
applyRegion(descriptor, record, cloneSnapshot(entry.data), stream, options);
|
|
133
|
+
appliedRegionIds.push(entry.id);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (options.restoreFocus === true && normalized.focus) {
|
|
137
|
+
syncStreamedWorldFocus2D(stream, options.auraRef, normalized.focus);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
ok: true,
|
|
142
|
+
reasonCode: null,
|
|
143
|
+
appliedRegionIds,
|
|
144
|
+
restoredFocus: options.restoreFocus === true && normalized.focus != null,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function saveStreamedWorldSnapshot2D(key, stream, auraRef = globalThis.aura, options = {}) {
|
|
149
|
+
const storage = resolveStorage(auraRef);
|
|
150
|
+
const snapshot = captureStreamedWorldSnapshot2D(stream, options);
|
|
151
|
+
if (!snapshot) {
|
|
152
|
+
return {
|
|
153
|
+
ok: false,
|
|
154
|
+
reasonCode: 'invalid_stream',
|
|
155
|
+
snapshot: null,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (!storageSave(storage, key, snapshot)) {
|
|
159
|
+
return {
|
|
160
|
+
ok: false,
|
|
161
|
+
reasonCode: 'storage_unavailable',
|
|
162
|
+
snapshot,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
ok: true,
|
|
167
|
+
reasonCode: null,
|
|
168
|
+
snapshot,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function loadStreamedWorldSnapshot2D(key, auraRef = globalThis.aura, fallback = null) {
|
|
173
|
+
const storage = resolveStorage(auraRef);
|
|
174
|
+
const snapshot = storageLoad(storage, key, fallback);
|
|
175
|
+
return normalizeSnapshot(snapshot);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function deleteStreamedWorldSnapshot2D(key, auraRef = globalThis.aura) {
|
|
179
|
+
return storageDelete(resolveStorage(auraRef), key);
|
|
180
|
+
}
|