@jgengine/core 0.8.0 → 0.10.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/CHANGELOG.md +36 -0
- package/dist/ai/flock.d.ts +36 -0
- package/dist/ai/flock.js +182 -0
- package/dist/ai/groupAssist.d.ts +19 -0
- package/dist/ai/groupAssist.js +59 -0
- package/dist/ai/laneSelect.d.ts +21 -0
- package/dist/ai/laneSelect.js +37 -0
- package/dist/ai/mobBrain.d.ts +68 -0
- package/dist/ai/mobBrain.js +115 -0
- package/dist/ai/spawnDirector.d.ts +13 -0
- package/dist/ai/spawnDirector.js +41 -17
- package/dist/ai/spawnPoint.d.ts +5 -0
- package/dist/ai/spawnPoint.js +5 -0
- package/dist/ai/threat.d.ts +2 -0
- package/dist/ai/threat.js +34 -0
- package/dist/audio/audioFalloff.d.ts +5 -2
- package/dist/audio/music.d.ts +53 -0
- package/dist/audio/music.js +34 -0
- package/dist/audio/synth.d.ts +60 -0
- package/dist/audio/synth.js +8 -0
- package/dist/authoring.d.ts +14 -0
- package/dist/authoring.js +14 -0
- package/dist/cartridge/runtime.d.ts +15 -0
- package/dist/cartridge/runtime.js +556 -0
- package/dist/cartridge/spec.d.ts +188 -0
- package/dist/cartridge/spec.js +19 -0
- package/dist/cartridge/validate.d.ts +2 -0
- package/dist/cartridge/validate.js +78 -0
- package/dist/combat/abilityKit.d.ts +17 -2
- package/dist/combat/abilityKit.js +62 -13
- package/dist/combat/castRunner.d.ts +40 -0
- package/dist/combat/castRunner.js +56 -0
- package/dist/combat/comboPoints.d.ts +14 -0
- package/dist/combat/comboPoints.js +52 -0
- package/dist/combat/defensiveWindow.d.ts +1 -1
- package/dist/combat/defensiveWindow.js +5 -3
- package/dist/combat/dotField.d.ts +43 -0
- package/dist/combat/dotField.js +48 -0
- package/dist/combat/projectiles.d.ts +33 -12
- package/dist/combat/projectiles.js +214 -129
- package/dist/combat/regenShield.d.ts +35 -0
- package/dist/combat/regenShield.js +45 -0
- package/dist/combat/resistance.d.ts +16 -4
- package/dist/combat/resistance.js +43 -7
- package/dist/combat/resourcePool.d.ts +20 -0
- package/dist/combat/resourcePool.js +55 -0
- package/dist/combat/shotOrigin.d.ts +52 -0
- package/dist/combat/shotOrigin.js +86 -0
- package/dist/combat/telegraph.d.ts +25 -0
- package/dist/combat/telegraph.js +47 -0
- package/dist/crafting/recipe.js +4 -1
- package/dist/devtools/devtools.d.ts +72 -24
- package/dist/devtools/devtools.js +449 -101
- package/dist/devtools/transformTunables.js +3 -3
- package/dist/devtools/tunableSchema.d.ts +140 -0
- package/dist/devtools/tunableSchema.js +476 -0
- package/dist/editor/commands.d.ts +65 -0
- package/dist/editor/commands.js +193 -0
- package/dist/editor/document.d.ts +40 -0
- package/dist/editor/document.js +153 -0
- package/dist/editor/index.d.ts +30 -0
- package/dist/editor/index.js +6 -0
- package/dist/editor/types.d.ts +69 -0
- package/dist/editor/types.js +29 -0
- package/dist/faction/factions.d.ts +33 -0
- package/dist/faction/factions.js +76 -0
- package/dist/faction/reputation.d.ts +32 -0
- package/dist/faction/reputation.js +82 -0
- package/dist/game/chat.d.ts +2 -0
- package/dist/game/chat.js +9 -1
- package/dist/game/chatFilter.d.ts +15 -0
- package/dist/game/chatFilter.js +55 -0
- package/dist/game/connectedPlayers.d.ts +28 -0
- package/dist/game/connectedPlayers.js +21 -0
- package/dist/game/controlGate.d.ts +4 -0
- package/dist/game/controlGate.js +7 -0
- package/dist/game/defineGame.d.ts +44 -1
- package/dist/game/defineGame.js +1 -0
- package/dist/game/events.d.ts +25 -0
- package/dist/game/gamePhase.d.ts +20 -0
- package/dist/game/gamePhase.js +21 -0
- package/dist/game/keyValueStore.d.ts +25 -0
- package/dist/game/keyValueStore.js +61 -0
- package/dist/game/levelSequence.d.ts +24 -2
- package/dist/game/levelSequence.js +51 -2
- package/dist/game/lootTable.d.ts +14 -1
- package/dist/game/lootTable.js +28 -7
- package/dist/game/modelAnimation.d.ts +8 -0
- package/dist/game/modelAnimation.js +18 -0
- package/dist/game/playableGame.d.ts +116 -4
- package/dist/game/playableGame.js +1 -1
- package/dist/game/quest.d.ts +7 -3
- package/dist/game/quest.js +17 -8
- package/dist/game/race.d.ts +39 -1
- package/dist/game/race.js +96 -11
- package/dist/game/recordBook.d.ts +27 -0
- package/dist/game/recordBook.js +86 -0
- package/dist/game/talents.d.ts +47 -0
- package/dist/game/talents.js +140 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/input/actionBindings.d.ts +2 -0
- package/dist/input/actionBindings.js +1 -0
- package/dist/input/axisInput.d.ts +33 -3
- package/dist/input/axisInput.js +60 -4
- package/dist/input/bindingOverrides.d.ts +25 -0
- package/dist/input/bindingOverrides.js +95 -0
- package/dist/input/pointerAxis.d.ts +30 -0
- package/dist/input/pointerAxis.js +31 -0
- package/dist/input/touchScheme.d.ts +6 -0
- package/dist/input/touchScheme.js +45 -7
- package/dist/interaction/contextMenu.d.ts +1 -0
- package/dist/interaction/contextMenu.js +1 -0
- package/dist/interaction/proximityPrompt.d.ts +3 -1
- package/dist/interaction/proximityPrompt.js +3 -3
- package/dist/meta/changelog.d.ts +1 -1
- package/dist/meta/changelog.js +44 -1
- package/dist/movement/dash.d.ts +3 -0
- package/dist/movement/dash.js +19 -5
- package/dist/movement/glideModel.d.ts +44 -0
- package/dist/movement/glideModel.js +54 -0
- package/dist/movement/grappleSwing.d.ts +34 -0
- package/dist/movement/grappleSwing.js +56 -0
- package/dist/movement/leaderTrail.d.ts +29 -0
- package/dist/movement/leaderTrail.js +67 -0
- package/dist/movement/movementModel.d.ts +4 -0
- package/dist/movement/movementModel.js +13 -0
- package/dist/movement/playerMovement.d.ts +41 -0
- package/dist/movement/playerMovement.js +181 -0
- package/dist/movement/steering.d.ts +27 -0
- package/dist/movement/steering.js +40 -0
- package/dist/multiplayer/feedWriteGate.d.ts +10 -0
- package/dist/multiplayer/feedWriteGate.js +12 -0
- package/dist/multiplayer/presenceModel.d.ts +14 -2
- package/dist/multiplayer/presenceModel.js +15 -3
- package/dist/nav/corridors.d.ts +30 -0
- package/dist/nav/corridors.js +69 -0
- package/dist/nav/navGrid.js +30 -4
- package/dist/nav/railGraph.d.ts +66 -0
- package/dist/nav/railGraph.js +129 -0
- package/dist/nav/timetable.d.ts +41 -0
- package/dist/nav/timetable.js +94 -0
- package/dist/physics/buoyancy.d.ts +6 -0
- package/dist/physics/buoyancy.js +14 -0
- package/dist/physics/flowTube.d.ts +32 -0
- package/dist/physics/flowTube.js +64 -0
- package/dist/physics/forceVolume.d.ts +27 -0
- package/dist/physics/forceVolume.js +38 -0
- package/dist/physics/kinematicVehicle.d.ts +52 -0
- package/dist/physics/kinematicVehicle.js +81 -0
- package/dist/physics/physicsWorld.d.ts +13 -6
- package/dist/physics/physicsWorld.js +169 -40
- package/dist/physics/ragdoll.js +1 -1
- package/dist/physics/vehicleBody.js +2 -1
- package/dist/random/rng.d.ts +2 -0
- package/dist/random/rng.js +2 -0
- package/dist/random/seedLink.d.ts +5 -0
- package/dist/random/seedLink.js +35 -0
- package/dist/render/postProcessing.d.ts +56 -0
- package/dist/render/postProcessing.js +1 -0
- package/dist/runtime/adapter.d.ts +19 -0
- package/dist/runtime/adapter.js +11 -5
- package/dist/runtime/cameraDirector.d.ts +6 -1
- package/dist/runtime/cameraDirector.js +6 -0
- package/dist/runtime/commandRunner.d.ts +2 -2
- package/dist/runtime/commandRunner.js +2 -2
- package/dist/runtime/gameContext.d.ts +72 -8
- package/dist/runtime/gameContext.js +374 -61
- package/dist/runtime/gameRuntime.d.ts +5 -1
- package/dist/runtime/gameRuntime.js +13 -12
- package/dist/runtime/hostPersistence.d.ts +9 -1
- package/dist/runtime/hostPersistence.js +23 -8
- package/dist/runtime/hostedGameRunner.d.ts +49 -0
- package/dist/runtime/hostedGameRunner.js +62 -0
- package/dist/runtime/hostedWorldSession.d.ts +65 -0
- package/dist/runtime/hostedWorldSession.js +57 -0
- package/dist/runtime/inputSnapshot.d.ts +18 -0
- package/dist/runtime/inputSnapshot.js +7 -0
- package/dist/runtime/motionIntents.d.ts +16 -6
- package/dist/runtime/motionIntents.js +31 -2
- package/dist/runtime/snapshot.d.ts +1 -0
- package/dist/runtime/snapshot.js +1 -1
- package/dist/runtime/visibility.d.ts +74 -0
- package/dist/runtime/visibility.js +127 -0
- package/dist/runtime/worldChannel.d.ts +58 -0
- package/dist/runtime/worldChannel.js +69 -0
- package/dist/runtime/worldMirror.d.ts +24 -0
- package/dist/runtime/worldMirror.js +31 -0
- package/dist/runtime/worldReplication.d.ts +46 -0
- package/dist/runtime/worldReplication.js +185 -0
- package/dist/runtime/worldSnapshot.d.ts +17 -0
- package/dist/runtime/worldSnapshot.js +15 -0
- package/dist/scene/assetCatalog.d.ts +1 -0
- package/dist/scene/colliders.d.ts +50 -0
- package/dist/scene/colliders.js +101 -0
- package/dist/scene/entityStats.d.ts +4 -0
- package/dist/scene/entityStats.js +21 -0
- package/dist/scene/entityStore.d.ts +51 -5
- package/dist/scene/entityStore.js +119 -12
- package/dist/scene/objectQuery.d.ts +13 -2
- package/dist/scene/objectQuery.js +34 -2
- package/dist/scene/objectStore.d.ts +2 -0
- package/dist/scene/objectStore.js +31 -12
- package/dist/scene/sceneRaycast.d.ts +80 -0
- package/dist/scene/sceneRaycast.js +284 -0
- package/dist/scene/spatial.d.ts +11 -16
- package/dist/scene/spatial.js +99 -38
- package/dist/sensor/recordingBuffer.d.ts +6 -0
- package/dist/sensor/recordingBuffer.js +7 -0
- package/dist/sensor/replayLoop.d.ts +39 -0
- package/dist/sensor/replayLoop.js +64 -0
- package/dist/sensor/visionCone.d.ts +31 -0
- package/dist/sensor/visionCone.js +72 -0
- package/dist/session/extraction.d.ts +2 -2
- package/dist/session/extraction.js +13 -2
- package/dist/settings/settingsModel.d.ts +97 -0
- package/dist/settings/settingsModel.js +100 -0
- package/dist/stats/statModifiers.d.ts +5 -2
- package/dist/stats/statModifiers.js +32 -14
- package/dist/store/observableKeyedStore.d.ts +4 -0
- package/dist/store/observableKeyedStore.js +17 -2
- package/dist/survival/decayMeter.d.ts +1 -1
- package/dist/survival/decayMeter.js +0 -1
- package/dist/tactics/fallingGrid.d.ts +2 -2
- package/dist/tactics/fallingGrid.js +2 -2
- package/dist/time/beatClock.d.ts +18 -0
- package/dist/time/beatClock.js +24 -0
- package/dist/time/idleProgress.d.ts +29 -0
- package/dist/time/idleProgress.js +31 -0
- package/dist/time/serverTick.d.ts +7 -1
- package/dist/time/serverTick.js +27 -4
- package/dist/time/stateSchedule.d.ts +57 -0
- package/dist/time/stateSchedule.js +121 -0
- package/dist/turn/commit.d.ts +2 -2
- package/dist/turn/commit.js +2 -2
- package/dist/ui/gameLayout.d.ts +125 -0
- package/dist/ui/gameLayout.js +129 -0
- package/dist/ui/hudLayout.d.ts +58 -0
- package/dist/ui/hudLayout.js +207 -0
- package/dist/ui/hudScale.d.ts +44 -0
- package/dist/ui/hudScale.js +55 -0
- package/dist/ui/orientation.d.ts +39 -0
- package/dist/ui/orientation.js +49 -0
- package/dist/ui/swingTimer.d.ts +42 -0
- package/dist/ui/swingTimer.js +38 -0
- package/dist/visibility/assetStreaming.d.ts +66 -0
- package/dist/visibility/assetStreaming.js +201 -0
- package/dist/visibility/bounds.d.ts +66 -0
- package/dist/visibility/bounds.js +113 -0
- package/dist/visibility/camera.d.ts +21 -0
- package/dist/visibility/camera.js +3 -0
- package/dist/visibility/config.d.ts +21 -0
- package/dist/visibility/config.js +1 -0
- package/dist/visibility/diagnostics.d.ts +26 -0
- package/dist/visibility/diagnostics.js +36 -0
- package/dist/visibility/distance.d.ts +11 -0
- package/dist/visibility/distance.js +30 -0
- package/dist/visibility/frustum.d.ts +47 -0
- package/dist/visibility/frustum.js +186 -0
- package/dist/visibility/occlusion.d.ts +36 -0
- package/dist/visibility/occlusion.js +45 -0
- package/dist/visibility/settings.d.ts +75 -0
- package/dist/visibility/settings.js +49 -0
- package/dist/visibility/simulationCulling.d.ts +34 -0
- package/dist/visibility/simulationCulling.js +36 -0
- package/dist/visibility/spatialIndex.d.ts +45 -0
- package/dist/visibility/spatialIndex.js +212 -0
- package/dist/visibility/visibilitySystem.d.ts +90 -0
- package/dist/visibility/visibilitySystem.js +257 -0
- package/dist/world/buildings.d.ts +6 -0
- package/dist/world/buildings.js +152 -0
- package/dist/world/carve.d.ts +7 -2
- package/dist/world/carve.js +17 -7
- package/dist/world/cellStates.d.ts +45 -0
- package/dist/world/cellStates.js +103 -0
- package/dist/world/environmentSummary.d.ts +21 -4
- package/dist/world/environmentSummary.js +22 -3
- package/dist/world/features.d.ts +185 -8
- package/dist/world/features.js +64 -6
- package/dist/world/gridInstances.d.ts +7 -8
- package/dist/world/gridInstances.js +145 -7
- package/dist/world/lod.d.ts +17 -0
- package/dist/world/lod.js +66 -0
- package/dist/world/mapLayers.d.ts +60 -0
- package/dist/world/mapLayers.js +44 -0
- package/dist/world/massing.d.ts +45 -0
- package/dist/world/massing.js +581 -0
- package/dist/world/minimap.d.ts +13 -1
- package/dist/world/minimap.js +21 -2
- package/dist/world/roads.d.ts +47 -0
- package/dist/world/roads.js +146 -0
- package/dist/world/streets.d.ts +80 -0
- package/dist/world/streets.js +144 -0
- package/dist/world/terrain.d.ts +69 -3
- package/dist/world/terrain.js +309 -16
- package/dist/world/water.d.ts +7 -0
- package/dist/world/water.js +19 -4
- package/dist/world/weather.d.ts +3 -18
- package/dist/world/weather.js +4 -17
- package/dist/world/windZones.d.ts +47 -0
- package/dist/world/windZones.js +59 -0
- package/llms.txt +3013 -1726
- package/package.json +12 -2
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
export function isPanelDraggable(state, id) {
|
|
2
|
+
return state.panels[id] !== undefined && (state.editing || !state.locked);
|
|
3
|
+
}
|
|
4
|
+
export const HUD_ANCHOR_FRACTIONS = {
|
|
5
|
+
"top-left": { fx: 0, fy: 0 },
|
|
6
|
+
top: { fx: 0.5, fy: 0 },
|
|
7
|
+
"top-right": { fx: 1, fy: 0 },
|
|
8
|
+
left: { fx: 0, fy: 0.5 },
|
|
9
|
+
center: { fx: 0.5, fy: 0.5 },
|
|
10
|
+
right: { fx: 1, fy: 0.5 },
|
|
11
|
+
"bottom-left": { fx: 0, fy: 1 },
|
|
12
|
+
bottom: { fx: 0.5, fy: 1 },
|
|
13
|
+
"bottom-right": { fx: 1, fy: 1 },
|
|
14
|
+
};
|
|
15
|
+
const HUD_ANCHORS = Object.keys(HUD_ANCHOR_FRACTIONS);
|
|
16
|
+
export function isHudAnchor(value) {
|
|
17
|
+
return typeof value === "string" && value in HUD_ANCHOR_FRACTIONS;
|
|
18
|
+
}
|
|
19
|
+
export function anchoredPlacement(anchor, inset) {
|
|
20
|
+
const { fx, fy } = HUD_ANCHOR_FRACTIONS[anchor];
|
|
21
|
+
return {
|
|
22
|
+
anchor,
|
|
23
|
+
dx: fx === 1 ? -inset.x : inset.x,
|
|
24
|
+
dy: fy === 1 ? -inset.y : inset.y,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function nearestAnchor(rect, viewport) {
|
|
28
|
+
const cx = viewport.width > 0 ? (rect.x + rect.width / 2) / viewport.width : 0.5;
|
|
29
|
+
const cy = viewport.height > 0 ? (rect.y + rect.height / 2) / viewport.height : 0.5;
|
|
30
|
+
let best = "center";
|
|
31
|
+
let bestDist = Infinity;
|
|
32
|
+
for (const anchor of HUD_ANCHORS) {
|
|
33
|
+
const { fx, fy } = HUD_ANCHOR_FRACTIONS[anchor];
|
|
34
|
+
const dist = (cx - fx) * (cx - fx) + (cy - fy) * (cy - fy);
|
|
35
|
+
if (dist < bestDist) {
|
|
36
|
+
bestDist = dist;
|
|
37
|
+
best = anchor;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return best;
|
|
41
|
+
}
|
|
42
|
+
export function clampRect(rect, viewport) {
|
|
43
|
+
return {
|
|
44
|
+
x: Math.max(0, Math.min(rect.x, viewport.width - rect.width)),
|
|
45
|
+
y: Math.max(0, Math.min(rect.y, viewport.height - rect.height)),
|
|
46
|
+
width: rect.width,
|
|
47
|
+
height: rect.height,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function placementFromRect(rect, viewport, snap = 1) {
|
|
51
|
+
const clamped = clampRect(rect, viewport);
|
|
52
|
+
const anchor = nearestAnchor(clamped, viewport);
|
|
53
|
+
const { fx, fy } = HUD_ANCHOR_FRACTIONS[anchor];
|
|
54
|
+
const step = snap > 0 ? snap : 1;
|
|
55
|
+
const dx = clamped.x + fx * clamped.width - fx * viewport.width;
|
|
56
|
+
const dy = clamped.y + fy * clamped.height - fy * viewport.height;
|
|
57
|
+
return {
|
|
58
|
+
anchor,
|
|
59
|
+
dx: Math.round(dx / step) * step,
|
|
60
|
+
dy: Math.round(dy / step) * step,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function rectFromPlacement(placement, size, viewport) {
|
|
64
|
+
const { fx, fy } = HUD_ANCHOR_FRACTIONS[placement.anchor];
|
|
65
|
+
return {
|
|
66
|
+
x: fx * viewport.width + placement.dx - fx * size.width,
|
|
67
|
+
y: fy * viewport.height + placement.dy - fy * size.height,
|
|
68
|
+
width: size.width,
|
|
69
|
+
height: size.height,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function parseSerialized(raw) {
|
|
73
|
+
const out = new Map();
|
|
74
|
+
let data;
|
|
75
|
+
try {
|
|
76
|
+
data = JSON.parse(raw);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
if (typeof data !== "object" || data === null)
|
|
82
|
+
return out;
|
|
83
|
+
const panels = data.panels;
|
|
84
|
+
if (typeof panels !== "object" || panels === null)
|
|
85
|
+
return out;
|
|
86
|
+
for (const [id, value] of Object.entries(panels)) {
|
|
87
|
+
if (typeof value !== "object" || value === null)
|
|
88
|
+
continue;
|
|
89
|
+
const { anchor, dx, dy } = value;
|
|
90
|
+
if (!isHudAnchor(anchor))
|
|
91
|
+
continue;
|
|
92
|
+
if (typeof dx !== "number" || !Number.isFinite(dx))
|
|
93
|
+
continue;
|
|
94
|
+
if (typeof dy !== "number" || !Number.isFinite(dy))
|
|
95
|
+
continue;
|
|
96
|
+
out.set(id, { anchor, dx, dy });
|
|
97
|
+
}
|
|
98
|
+
return out;
|
|
99
|
+
}
|
|
100
|
+
export function createHudLayout(options) {
|
|
101
|
+
const snap = options?.snap ?? 1;
|
|
102
|
+
const defaults = new Map();
|
|
103
|
+
const pending = new Map();
|
|
104
|
+
let topZ = 0;
|
|
105
|
+
let state = { panels: {}, locked: options?.locked ?? true, editing: false };
|
|
106
|
+
const listeners = new Set();
|
|
107
|
+
const emit = () => {
|
|
108
|
+
for (const listener of [...listeners])
|
|
109
|
+
listener(state);
|
|
110
|
+
};
|
|
111
|
+
const setPanel = (panel) => {
|
|
112
|
+
state = { ...state, panels: { ...state.panels, [panel.id]: panel } };
|
|
113
|
+
};
|
|
114
|
+
return {
|
|
115
|
+
getState: () => state,
|
|
116
|
+
subscribe(listener) {
|
|
117
|
+
listeners.add(listener);
|
|
118
|
+
return () => listeners.delete(listener);
|
|
119
|
+
},
|
|
120
|
+
register(id, placement) {
|
|
121
|
+
defaults.set(id, placement);
|
|
122
|
+
if (state.panels[id] !== undefined)
|
|
123
|
+
return;
|
|
124
|
+
const override = pending.get(id);
|
|
125
|
+
setPanel({
|
|
126
|
+
id,
|
|
127
|
+
placement: override ?? placement,
|
|
128
|
+
z: ++topZ,
|
|
129
|
+
moved: override !== undefined,
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
move(id, rect, viewport) {
|
|
133
|
+
const panel = state.panels[id];
|
|
134
|
+
if (panel === undefined)
|
|
135
|
+
return;
|
|
136
|
+
const placement = placementFromRect(rect, viewport, snap);
|
|
137
|
+
setPanel({ ...panel, placement, moved: true });
|
|
138
|
+
emit();
|
|
139
|
+
},
|
|
140
|
+
bringToFront(id) {
|
|
141
|
+
const panel = state.panels[id];
|
|
142
|
+
if (panel === undefined || panel.z === topZ)
|
|
143
|
+
return;
|
|
144
|
+
setPanel({ ...panel, z: ++topZ });
|
|
145
|
+
emit();
|
|
146
|
+
},
|
|
147
|
+
setLocked(locked) {
|
|
148
|
+
if (state.locked === locked)
|
|
149
|
+
return;
|
|
150
|
+
state = { ...state, locked };
|
|
151
|
+
emit();
|
|
152
|
+
},
|
|
153
|
+
setEditing(editing) {
|
|
154
|
+
if (state.editing === editing)
|
|
155
|
+
return;
|
|
156
|
+
state = { ...state, editing };
|
|
157
|
+
emit();
|
|
158
|
+
},
|
|
159
|
+
reset(id) {
|
|
160
|
+
const ids = id === undefined ? Object.keys(state.panels) : [id];
|
|
161
|
+
let changed = false;
|
|
162
|
+
for (const panelId of ids) {
|
|
163
|
+
pending.delete(panelId);
|
|
164
|
+
const panel = state.panels[panelId];
|
|
165
|
+
const fallback = defaults.get(panelId);
|
|
166
|
+
if (panel === undefined || fallback === undefined || !panel.moved)
|
|
167
|
+
continue;
|
|
168
|
+
setPanel({ ...panel, placement: fallback, moved: false });
|
|
169
|
+
changed = true;
|
|
170
|
+
}
|
|
171
|
+
if (changed)
|
|
172
|
+
emit();
|
|
173
|
+
},
|
|
174
|
+
serialize() {
|
|
175
|
+
const panels = {};
|
|
176
|
+
for (const panel of Object.values(state.panels)) {
|
|
177
|
+
if (panel.moved)
|
|
178
|
+
panels[panel.id] = panel.placement;
|
|
179
|
+
}
|
|
180
|
+
for (const [id, placement] of pending) {
|
|
181
|
+
if (state.panels[id] === undefined)
|
|
182
|
+
panels[id] = placement;
|
|
183
|
+
}
|
|
184
|
+
const data = { v: 1, panels };
|
|
185
|
+
return JSON.stringify(data);
|
|
186
|
+
},
|
|
187
|
+
hydrate(raw) {
|
|
188
|
+
if (raw === null || raw === undefined || raw === "")
|
|
189
|
+
return;
|
|
190
|
+
const parsed = parseSerialized(raw);
|
|
191
|
+
if (parsed.size === 0)
|
|
192
|
+
return;
|
|
193
|
+
let changed = false;
|
|
194
|
+
for (const [id, placement] of parsed) {
|
|
195
|
+
const panel = state.panels[id];
|
|
196
|
+
if (panel === undefined) {
|
|
197
|
+
pending.set(id, placement);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
setPanel({ ...panel, placement, moved: true });
|
|
201
|
+
changed = true;
|
|
202
|
+
}
|
|
203
|
+
if (changed)
|
|
204
|
+
emit();
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { HudRect, HudSize } from "./hudLayout.js";
|
|
2
|
+
/** Where a game is meant to be played. `"web"` alone keeps today's desktop-first HUD; adding `"mobile"` turns on design-resolution fit scaling on compact displays. */
|
|
3
|
+
export type HudPlatform = "web" | "mobile";
|
|
4
|
+
/**
|
|
5
|
+
* Design-resolution fit for the HUD surface. The game authors its UI against
|
|
6
|
+
* `designSize`; on smaller viewports the whole HUD scales down by the limiting
|
|
7
|
+
* axis ratio, clamped to `[minScale, maxScale]`, so panels keep their layout
|
|
8
|
+
* and simply shrink instead of overflowing.
|
|
9
|
+
*/
|
|
10
|
+
export interface HudFitConfig {
|
|
11
|
+
designSize?: HudSize;
|
|
12
|
+
/** Floor for the computed scale — below this, shrinking further makes text unreadable. Default 0.4. */
|
|
13
|
+
minScale?: number;
|
|
14
|
+
/** Ceiling for the computed scale. Default 1 (never upscale past authored size). */
|
|
15
|
+
maxScale?: number;
|
|
16
|
+
}
|
|
17
|
+
/** Per-game HUD viewport declaration carried on `PlayableGame.hudFit`; `mobile` overrides the fit on compact displays so the owner can tune the phone layout separately. */
|
|
18
|
+
export interface HudViewportConfig extends HudFitConfig {
|
|
19
|
+
mobile?: HudFitConfig;
|
|
20
|
+
}
|
|
21
|
+
export declare const DEFAULT_HUD_DESIGN_SIZE: HudSize;
|
|
22
|
+
export declare const DEFAULT_HUD_MIN_SCALE = 0.4;
|
|
23
|
+
export declare const DEFAULT_HUD_MAX_SCALE = 1;
|
|
24
|
+
export declare function resolveHudFit(config: HudViewportConfig | undefined, mobile: boolean): Required<HudFitConfig>;
|
|
25
|
+
/**
|
|
26
|
+
* The one scaling rule for every display: the ratio of the live viewport to
|
|
27
|
+
* the authored design size along the limiting axis, clamped. 1 on a viewport
|
|
28
|
+
* at or above design size; smoothly below 1 down to `minScale` on phones.
|
|
29
|
+
*/
|
|
30
|
+
export declare function hudScaleForViewport(fit: Required<HudFitConfig>, viewport: HudSize): number;
|
|
31
|
+
export interface HudOverflow {
|
|
32
|
+
id: string;
|
|
33
|
+
left: number;
|
|
34
|
+
top: number;
|
|
35
|
+
right: number;
|
|
36
|
+
bottom: number;
|
|
37
|
+
}
|
|
38
|
+
/** Non-null when any edge of `rect` falls outside `viewport` by more than `tolerance` px; each field is the overflow distance past that edge (0 when inside). */
|
|
39
|
+
export declare function rectOverflow(rect: HudRect, viewport: HudSize, tolerance?: number): Omit<HudOverflow, "id"> | null;
|
|
40
|
+
/** Every panel rect that escapes the viewport — the data behind the HUD overflow gate. */
|
|
41
|
+
export declare function overflowingPanels(panels: readonly {
|
|
42
|
+
id: string;
|
|
43
|
+
rect: HudRect;
|
|
44
|
+
}[], viewport: HudSize, tolerance?: number): HudOverflow[];
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export const DEFAULT_HUD_DESIGN_SIZE = { width: 1600, height: 900 };
|
|
2
|
+
export const DEFAULT_HUD_MIN_SCALE = 0.4;
|
|
3
|
+
export const DEFAULT_HUD_MAX_SCALE = 1;
|
|
4
|
+
export function resolveHudFit(config, mobile) {
|
|
5
|
+
const base = {
|
|
6
|
+
designSize: config?.designSize ?? DEFAULT_HUD_DESIGN_SIZE,
|
|
7
|
+
minScale: config?.minScale ?? DEFAULT_HUD_MIN_SCALE,
|
|
8
|
+
maxScale: config?.maxScale ?? DEFAULT_HUD_MAX_SCALE,
|
|
9
|
+
};
|
|
10
|
+
if (!mobile || config?.mobile === undefined)
|
|
11
|
+
return base;
|
|
12
|
+
return {
|
|
13
|
+
designSize: config.mobile.designSize ?? base.designSize,
|
|
14
|
+
minScale: config.mobile.minScale ?? base.minScale,
|
|
15
|
+
maxScale: config.mobile.maxScale ?? base.maxScale,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The one scaling rule for every display: the ratio of the live viewport to
|
|
20
|
+
* the authored design size along the limiting axis, clamped. 1 on a viewport
|
|
21
|
+
* at or above design size; smoothly below 1 down to `minScale` on phones.
|
|
22
|
+
*/
|
|
23
|
+
export function hudScaleForViewport(fit, viewport) {
|
|
24
|
+
if (!Number.isFinite(viewport.width) ||
|
|
25
|
+
!Number.isFinite(viewport.height) ||
|
|
26
|
+
viewport.width <= 0 ||
|
|
27
|
+
viewport.height <= 0 ||
|
|
28
|
+
fit.designSize.width <= 0 ||
|
|
29
|
+
fit.designSize.height <= 0) {
|
|
30
|
+
return 1;
|
|
31
|
+
}
|
|
32
|
+
const ratio = Math.min(viewport.width / fit.designSize.width, viewport.height / fit.designSize.height);
|
|
33
|
+
return Math.min(fit.maxScale, Math.max(fit.minScale, ratio));
|
|
34
|
+
}
|
|
35
|
+
/** Non-null when any edge of `rect` falls outside `viewport` by more than `tolerance` px; each field is the overflow distance past that edge (0 when inside). */
|
|
36
|
+
export function rectOverflow(rect, viewport, tolerance = 1.5) {
|
|
37
|
+
const left = Math.max(0, -rect.x);
|
|
38
|
+
const top = Math.max(0, -rect.y);
|
|
39
|
+
const right = Math.max(0, rect.x + rect.width - viewport.width);
|
|
40
|
+
const bottom = Math.max(0, rect.y + rect.height - viewport.height);
|
|
41
|
+
if (left <= tolerance && top <= tolerance && right <= tolerance && bottom <= tolerance)
|
|
42
|
+
return null;
|
|
43
|
+
const round = (n) => Math.round(n * 10) / 10;
|
|
44
|
+
return { left: round(left), top: round(top), right: round(right), bottom: round(bottom) };
|
|
45
|
+
}
|
|
46
|
+
/** Every panel rect that escapes the viewport — the data behind the HUD overflow gate. */
|
|
47
|
+
export function overflowingPanels(panels, viewport, tolerance = 1.5) {
|
|
48
|
+
const out = [];
|
|
49
|
+
for (const panel of panels) {
|
|
50
|
+
const overflow = rectOverflow(panel.rect, viewport, tolerance);
|
|
51
|
+
if (overflow !== null)
|
|
52
|
+
out.push({ id: panel.id, ...overflow });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game-level orientation contract. A game declares how it supports phone
|
|
3
|
+
* orientations; the shell resolves that against the live orientation to decide
|
|
4
|
+
* whether to show a dismissible rotate hint (advisory) or a full-screen gate
|
|
5
|
+
* that blocks gameplay until the device is turned (required).
|
|
6
|
+
*/
|
|
7
|
+
/** How a game supports a phone orientation on coarse-pointer displays. */
|
|
8
|
+
export type MobileOrientationRule = "any" | "portrait" | "landscape" | "portrait-required" | "landscape-required" | "unsupported";
|
|
9
|
+
/** Object form of the `orientation` field: the strict per-platform contract. */
|
|
10
|
+
export interface GameOrientationConfig {
|
|
11
|
+
/** Orientation contract on coarse-pointer / phone displays. Default `"any"`. */
|
|
12
|
+
mobile?: MobileOrientationRule;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The `orientation` field of a game definition. Legacy shorthand `"landscape"`
|
|
16
|
+
* / `"portrait"` stays advisory (a dismissible rotate hint, never a gate). The
|
|
17
|
+
* object form `{ mobile: "landscape-required" }` is the strict contract that
|
|
18
|
+
* blocks gameplay behind the rotate screen until the device is turned.
|
|
19
|
+
*/
|
|
20
|
+
export type GameOrientation = "landscape" | "portrait" | GameOrientationConfig;
|
|
21
|
+
/** A concrete device orientation. */
|
|
22
|
+
export type LayoutOrientation = "portrait" | "landscape";
|
|
23
|
+
/** The resolved orientation contract for a platform: whether it's supported, gated, or merely preferred. */
|
|
24
|
+
export interface OrientationRequirement {
|
|
25
|
+
/** False only for `"unsupported"` — the game declares it isn't built for phones. */
|
|
26
|
+
supported: boolean;
|
|
27
|
+
/** Orientation gameplay is hard-gated to; `null` when there is no gate. */
|
|
28
|
+
required: LayoutOrientation | null;
|
|
29
|
+
/** Orientation the game reads best in; drives an advisory hint when not required. */
|
|
30
|
+
preferred: LayoutOrientation | null;
|
|
31
|
+
}
|
|
32
|
+
/** Normalize the `orientation` field (legacy string or object) to a single mobile rule. */
|
|
33
|
+
export declare function resolveMobileOrientationRule(orientation: GameOrientation | undefined): MobileOrientationRule;
|
|
34
|
+
/** Resolve the game's orientation declaration into a concrete requirement for a platform. Desktop is always unconstrained. */
|
|
35
|
+
export declare function resolveOrientationRequirement(orientation: GameOrientation | undefined, platform: "mobile" | "desktop"): OrientationRequirement;
|
|
36
|
+
/** The rotate gate blocks gameplay: a hard requirement (or `unsupported`) the live orientation doesn't satisfy. */
|
|
37
|
+
export declare function orientationGateActive(requirement: OrientationRequirement, liveOrientation: LayoutOrientation): boolean;
|
|
38
|
+
/** An advisory rotate hint applies: a preference (not a hard gate) the live orientation doesn't satisfy. */
|
|
39
|
+
export declare function orientationHintActive(requirement: OrientationRequirement, liveOrientation: LayoutOrientation): boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The game-level orientation contract. A game declares how it supports phone
|
|
3
|
+
* orientations; the shell resolves that against the live orientation to decide
|
|
4
|
+
* whether to show a dismissible rotate hint (advisory) or a full-screen gate
|
|
5
|
+
* that blocks gameplay until the device is turned (required).
|
|
6
|
+
*/
|
|
7
|
+
/** Normalize the `orientation` field (legacy string or object) to a single mobile rule. */
|
|
8
|
+
export function resolveMobileOrientationRule(orientation) {
|
|
9
|
+
if (orientation === undefined)
|
|
10
|
+
return "any";
|
|
11
|
+
if (orientation === "landscape")
|
|
12
|
+
return "landscape";
|
|
13
|
+
if (orientation === "portrait")
|
|
14
|
+
return "portrait";
|
|
15
|
+
return orientation.mobile ?? "any";
|
|
16
|
+
}
|
|
17
|
+
/** Resolve the game's orientation declaration into a concrete requirement for a platform. Desktop is always unconstrained. */
|
|
18
|
+
export function resolveOrientationRequirement(orientation, platform) {
|
|
19
|
+
if (platform === "desktop")
|
|
20
|
+
return { supported: true, required: null, preferred: null };
|
|
21
|
+
const rule = resolveMobileOrientationRule(orientation);
|
|
22
|
+
switch (rule) {
|
|
23
|
+
case "unsupported":
|
|
24
|
+
return { supported: false, required: null, preferred: null };
|
|
25
|
+
case "landscape-required":
|
|
26
|
+
return { supported: true, required: "landscape", preferred: "landscape" };
|
|
27
|
+
case "portrait-required":
|
|
28
|
+
return { supported: true, required: "portrait", preferred: "portrait" };
|
|
29
|
+
case "landscape":
|
|
30
|
+
return { supported: true, required: null, preferred: "landscape" };
|
|
31
|
+
case "portrait":
|
|
32
|
+
return { supported: true, required: null, preferred: "portrait" };
|
|
33
|
+
case "any":
|
|
34
|
+
return { supported: true, required: null, preferred: null };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** The rotate gate blocks gameplay: a hard requirement (or `unsupported`) the live orientation doesn't satisfy. */
|
|
38
|
+
export function orientationGateActive(requirement, liveOrientation) {
|
|
39
|
+
if (!requirement.supported)
|
|
40
|
+
return true;
|
|
41
|
+
return requirement.required !== null && requirement.required !== liveOrientation;
|
|
42
|
+
}
|
|
43
|
+
/** An advisory rotate hint applies: a preference (not a hard gate) the live orientation doesn't satisfy. */
|
|
44
|
+
export function orientationHintActive(requirement, liveOrientation) {
|
|
45
|
+
return (requirement.supported &&
|
|
46
|
+
requirement.required === null &&
|
|
47
|
+
requirement.preferred !== null &&
|
|
48
|
+
requirement.preferred !== liveOrientation);
|
|
49
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** The local player's auto-attack state for one frame. `swingTimer` counts DOWN in seconds to 0 (= a swing lands). */
|
|
2
|
+
export interface SwingPlayerInput {
|
|
3
|
+
autoAttack: boolean;
|
|
4
|
+
swingTimer: number;
|
|
5
|
+
weapon: {
|
|
6
|
+
speed: number;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
/** The current target, or the fields the bar needs from it. */
|
|
10
|
+
export interface SwingTargetInput {
|
|
11
|
+
dead: boolean;
|
|
12
|
+
/** Entity kind; an `"object"` target (a node/chest) never shows a swing bar. */
|
|
13
|
+
kind: string;
|
|
14
|
+
}
|
|
15
|
+
/** Whether the bar shows a "ready" label or the seconds-remaining countdown. */
|
|
16
|
+
export type SwingLabelKind = "ready" | "seconds";
|
|
17
|
+
/** One frame of swing-bar state plus the cursor (`nextPeriod`/`nextTimer`) the caller carries back into the next call. */
|
|
18
|
+
export interface SwingTimerState {
|
|
19
|
+
/** Whether the bar should render at all. */
|
|
20
|
+
visible: boolean;
|
|
21
|
+
/** Fill 0..1, growing toward 1 as the next swing nears. */
|
|
22
|
+
frac: number;
|
|
23
|
+
/** True the moment the swing is ready to land. */
|
|
24
|
+
ready: boolean;
|
|
25
|
+
labelKind: SwingLabelKind;
|
|
26
|
+
/** Seconds remaining until the next swing (0 when ready). */
|
|
27
|
+
seconds: number;
|
|
28
|
+
/** Recovered swing period this frame — pass back as `prevPeriod` next call. */
|
|
29
|
+
nextPeriod: number;
|
|
30
|
+
/** This frame's timer — pass back as `prevTimer` next call to detect the reset edge. */
|
|
31
|
+
nextTimer: number;
|
|
32
|
+
}
|
|
33
|
+
/** Threshold above which a timer jump is treated as a fresh swing (period reset). */
|
|
34
|
+
export declare const SWING_EDGE_EPSILON = 0.0001;
|
|
35
|
+
/**
|
|
36
|
+
* Pure swing-timer bar state — no hidden state, no clock, no DOM. The caller
|
|
37
|
+
* threads `prevPeriod`/`prevTimer` back each frame. The period is recovered on
|
|
38
|
+
* the reset edge (when `swingTimer` jumps up = a new swing began) as
|
|
39
|
+
* `max(swingTimer, weapon.speed)`, so the fill is correct even without knowing
|
|
40
|
+
* the weapon's exact cadence. Hidden unless auto-attacking a live, non-object target.
|
|
41
|
+
*/
|
|
42
|
+
export declare function swingTimerState(player: SwingPlayerInput, target: SwingTargetInput | null, prevPeriod: number, prevTimer: number): SwingTimerState;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Threshold above which a timer jump is treated as a fresh swing (period reset). */
|
|
2
|
+
export const SWING_EDGE_EPSILON = 1e-4;
|
|
3
|
+
function clamp01(v) {
|
|
4
|
+
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
5
|
+
}
|
|
6
|
+
const HIDDEN = {
|
|
7
|
+
visible: false,
|
|
8
|
+
frac: 0,
|
|
9
|
+
ready: false,
|
|
10
|
+
labelKind: "seconds",
|
|
11
|
+
seconds: 0,
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Pure swing-timer bar state — no hidden state, no clock, no DOM. The caller
|
|
15
|
+
* threads `prevPeriod`/`prevTimer` back each frame. The period is recovered on
|
|
16
|
+
* the reset edge (when `swingTimer` jumps up = a new swing began) as
|
|
17
|
+
* `max(swingTimer, weapon.speed)`, so the fill is correct even without knowing
|
|
18
|
+
* the weapon's exact cadence. Hidden unless auto-attacking a live, non-object target.
|
|
19
|
+
*/
|
|
20
|
+
export function swingTimerState(player, target, prevPeriod, prevTimer) {
|
|
21
|
+
const swingTimer = player.swingTimer;
|
|
22
|
+
if (!player.autoAttack || target === null || target.dead || target.kind === "object") {
|
|
23
|
+
return { ...HIDDEN, nextPeriod: prevPeriod, nextTimer: swingTimer };
|
|
24
|
+
}
|
|
25
|
+
const isResetEdge = swingTimer > prevTimer + SWING_EDGE_EPSILON || prevPeriod <= 0;
|
|
26
|
+
const period = isResetEdge ? Math.max(swingTimer, player.weapon.speed) : prevPeriod;
|
|
27
|
+
const frac = period <= 0 ? 1 : clamp01(1 - swingTimer / period);
|
|
28
|
+
const ready = swingTimer <= 0;
|
|
29
|
+
return {
|
|
30
|
+
visible: true,
|
|
31
|
+
frac,
|
|
32
|
+
ready,
|
|
33
|
+
labelKind: ready ? "ready" : "seconds",
|
|
34
|
+
seconds: Math.max(0, swingTimer),
|
|
35
|
+
nextPeriod: period,
|
|
36
|
+
nextTimer: swingTimer,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { StreamingSettings } from "./settings.js";
|
|
2
|
+
import type { VisibilityStats } from "./diagnostics.js";
|
|
3
|
+
export type AssetLoadState = "queued" | "loading" | "loaded" | "unloaded" | "error";
|
|
4
|
+
export interface AssetLoadResult {
|
|
5
|
+
/** Approximate resident size, used for the memory budget and small-asset resident policy. */
|
|
6
|
+
readonly bytes?: number;
|
|
7
|
+
/** Opaque handle to the loaded resource (texture, mesh, buffer). */
|
|
8
|
+
readonly value?: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface CancelSignal {
|
|
11
|
+
readonly cancelled: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface AssetStreamingOptions {
|
|
14
|
+
/** Async loader. Must honor `signal.cancelled` and avoid committing work when it flips true. */
|
|
15
|
+
readonly load: (assetId: string, signal: CancelSignal) => Promise<AssetLoadResult>;
|
|
16
|
+
/** Release GPU/CPU resources for an asset. */
|
|
17
|
+
readonly unload?: (assetId: string) => void;
|
|
18
|
+
readonly settings?: Partial<StreamingSettings>;
|
|
19
|
+
readonly now?: () => number;
|
|
20
|
+
}
|
|
21
|
+
export interface AssetRecord {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
state: AssetLoadState;
|
|
24
|
+
bytes: number;
|
|
25
|
+
priority: number;
|
|
26
|
+
refCount: number;
|
|
27
|
+
pinned: boolean;
|
|
28
|
+
lastActiveMs: number;
|
|
29
|
+
value: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface StreamingStats {
|
|
32
|
+
queued: number;
|
|
33
|
+
loading: number;
|
|
34
|
+
loaded: number;
|
|
35
|
+
unloaded: number;
|
|
36
|
+
errored: number;
|
|
37
|
+
inFlight: number;
|
|
38
|
+
cancelled: number;
|
|
39
|
+
bytes: number;
|
|
40
|
+
}
|
|
41
|
+
export interface AssetStreamingSystem {
|
|
42
|
+
/** Demand an asset (near/in view). Deduplicated — an already loaded/loading/queued asset is never re-fetched concurrently. */
|
|
43
|
+
request(assetId: string, priority?: number): void;
|
|
44
|
+
/** Shared ownership by an active object. A retained asset (refCount > 0) is never auto-unloaded. */
|
|
45
|
+
retain(assetId: string): void;
|
|
46
|
+
release(assetId: string): void;
|
|
47
|
+
/** Pin resident regardless of distance/refcount/scene. */
|
|
48
|
+
pin(assetId: string): void;
|
|
49
|
+
unpin(assetId: string): void;
|
|
50
|
+
/** Refresh the "last needed" timestamp used by the grace-period unload. */
|
|
51
|
+
markActive(assetId: string): void;
|
|
52
|
+
/** Advance one frame: start up to the load budget, evict past-grace assets up to the unload budget. */
|
|
53
|
+
tick(dt: number): void;
|
|
54
|
+
/** Cancel an in-flight or queued request that is no longer needed. */
|
|
55
|
+
cancel(assetId: string): void;
|
|
56
|
+
stateOf(assetId: string): AssetLoadState | undefined;
|
|
57
|
+
isLoaded(assetId: string): boolean;
|
|
58
|
+
record(assetId: string): AssetRecord | undefined;
|
|
59
|
+
stats(): StreamingStats;
|
|
60
|
+
/** Merge asset counters into a per-frame VisibilityStats. */
|
|
61
|
+
applyTo(stats: VisibilityStats): void;
|
|
62
|
+
/** Resolve once every in-flight load settles — for deterministic tests. */
|
|
63
|
+
settle(): Promise<void>;
|
|
64
|
+
clear(): void;
|
|
65
|
+
}
|
|
66
|
+
export declare function createAssetStreamingSystem(options: AssetStreamingOptions): AssetStreamingSystem;
|