|
|
@@ -43,12 +43,13 @@ try {
|
|
|
async function scene(options, run) {
|
|
|
const costs = options.costs || [1, 1, 1]
|
|
|
const budget = options.budget || { maxContents: 2, maxDecodedBytes: 2048 }
|
|
|
- let time = 0, pose = 0, visible = [0], parentReady = true, renderRequested = false
|
|
|
+ let time = 0, pose = 0, visible = [0], parentReady = true, startAllowed = true, renderRequested = false
|
|
|
const loaded = [], added = [], disposed = [], byId = new Map(), waiting = new Map()
|
|
|
const control = createRegionLoadingController({
|
|
|
regions: costs.map((cost, id) => ({ id, contentCount: cost, decodedGeometryBytes: cost * 1024 })),
|
|
|
budget, distance: r => visible.includes(r.id) ? r.id + 1 : Infinity,
|
|
|
- readCameraKey: () => String(pose), now: () => time, canStart: () => parentReady,
|
|
|
+ readCameraKey: () => String(pose), now: () => time, canStart: () => parentReady && startAllowed,
|
|
|
+ canRetain: () => parentReady,
|
|
|
coverageReady: e => e.instance.covered,
|
|
|
load: r => {
|
|
|
loaded.push(r.id)
|
|
|
@@ -69,6 +70,7 @@ async function scene(options, run) {
|
|
|
async resolve(id) { waiting.get(id).resolve(); waiting.delete(id); await flush() },
|
|
|
async reject(id) { waiting.get(id).reject(new Error('load rejected')); waiting.delete(id); await flush() },
|
|
|
parent(value) { parentReady = value; control.refresh() },
|
|
|
+ allowStarts(value) { startAllowed = value; control.refresh() },
|
|
|
renderPending: () => renderRequested,
|
|
|
clearRenderRequest() { renderRequested = false },
|
|
|
checkBudget() {
|
|
|
@@ -205,4 +207,18 @@ await scene({ deferredIds: [1] }, async h => {
|
|
|
assert.deepEqual(h.disposed.slice().sort(), [0, 1], 'Cache and late model are each released once')
|
|
|
assert.equal(h.control.snapshot().length, 0)
|
|
|
})
|
|
|
+await scene({}, async h => {
|
|
|
+ await h.view([1])
|
|
|
+ const a = h.byId.get(0)
|
|
|
+ assert.equal(h.control.snapshot().find(e => e.id === 0).cached, true)
|
|
|
+ h.allowStarts(false) // parent is alive/visible, but temporarily not ready for new loads.
|
|
|
+ assert.deepEqual(h.disposed.slice(), [], 'A closed start gate must not invalidate a ready cache')
|
|
|
+ await h.view([0])
|
|
|
+ assert.deepEqual(h.loaded, [0, 1], 'Valid cached A can return while new starts are paused')
|
|
|
+ assert.equal(h.byId.get(0), a)
|
|
|
+ await h.view([2])
|
|
|
+ assert.deepEqual(h.loaded, [0, 1], 'The independent start gate still blocks a new region')
|
|
|
+ h.parent(false)
|
|
|
+ assert.equal(h.control.snapshot().length, 0, 'A genuinely invalid parent releases caches')
|
|
|
+})
|
|
|
console.log('PASS residency boundaries: hidden state, wakeup, LRU, budgets, pending reservation, failure and release')
|