mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 19:04:02 +00:00
fix(vessels): upload Navara chevrons and restore click focus
Fix delayed and growing mover bank commits, reject stale hidden model picks, and route world-focus through the engine. Strengthen vessel parity and performance checks without changing thresholds.
This commit is contained in:
1 parent
69a78710cc
commit
c8a4f3ed98
10 files changed
+96
-7
No files matched your search
@@ -215,7 +215,7 @@ async function main() {
|
|||||||
console.log(` Tag : ${TAG}`);
|
console.log(` Tag : ${TAG}`);
|
||||||
console.log(` Engine : ${ENGINE ?? 'viewer (Cesium)'}`);
|
console.log(` Engine : ${ENGINE ?? 'viewer (Cesium)'}`);
|
||||||
console.log(` Data : ${DATA_MODE}`);
|
console.log(` Data : ${DATA_MODE}`);
|
||||||
console.log(` Browser : ${HEADFUL ? 'headful (hardware renderer requested)' : 'headless (SwiftShader)'}`);
|
console.log(` Browser : ${HEADFUL ? 'headful (hardware renderer requested)' : 'headless (Metal)'}`);
|
||||||
console.log(` Ports : ${PORT_KEYS.join(', ')}\n`);
|
console.log(` Ports : ${PORT_KEYS.join(', ')}\n`);
|
||||||
for (const line of vesselCardProvenanceLines(DATA_MODE)) console.log(` ${line}`);
|
for (const line of vesselCardProvenanceLines(DATA_MODE)) console.log(` ${line}`);
|
||||||
console.log('');
|
console.log('');
|
||||||
@@ -238,7 +238,7 @@ async function main() {
|
|||||||
args: [
|
args: [
|
||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
...(!HEADFUL ? ['--use-gl=angle', '--use-angle=swiftshader'] : []),
|
'--use-angle=metal',
|
||||||
'--disable-dev-shm-usage',
|
'--disable-dev-shm-usage',
|
||||||
'--disable-background-timer-throttling',
|
'--disable-background-timer-throttling',
|
||||||
'--disable-renderer-backgrounding',
|
'--disable-renderer-backgrounding',
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ async function main() {
|
|||||||
'--no-sandbox',
|
'--no-sandbox',
|
||||||
'--disable-setuid-sandbox',
|
'--disable-setuid-sandbox',
|
||||||
'--use-gl=angle',
|
'--use-gl=angle',
|
||||||
'--use-angle=swiftshader',
|
'--use-angle=metal',
|
||||||
'--disable-dev-shm-usage',
|
'--disable-dev-shm-usage',
|
||||||
'--disable-background-timer-throttling',
|
'--disable-background-timer-throttling',
|
||||||
'--disable-renderer-backgrounding',
|
'--disable-renderer-backgrounding',
|
||||||
|
|||||||
@@ -378,7 +378,7 @@ test('refused canned destinations commit no location or POI state', () => {
|
|||||||
test('world-focus listener lifecycle is symmetric and idempotent', () => {
|
test('world-focus listener lifecycle is symmetric and idempotent', () => {
|
||||||
assert.match(ui, /registerWorldFocusRequestListener\(\s*window,/);
|
assert.match(ui, /registerWorldFocusRequestListener\(\s*window,/);
|
||||||
assert.match(ui, /routeWorldFocusRequest\(/);
|
assert.match(ui, /routeWorldFocusRequest\(/);
|
||||||
assert.match(ui, /flyToWorldTarget\(this\.viewer, detail\)/);
|
assert.match(ui, /flyToWorldTarget\(this\.engine \?\? this\.viewer, detail\)/);
|
||||||
assert.match(ui, /this\._removeWorldRequestFocusListener\?\.\(\);/);
|
assert.match(ui, /this\._removeWorldRequestFocusListener\?\.\(\);/);
|
||||||
assert.match(ui, /this\._removeWorldRequestFocusListener = null;/);
|
assert.match(ui, /this\._removeWorldRequestFocusListener = null;/);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -196,10 +196,11 @@ export function createCpuPicker({ projector, camera, movers, lines }) {
|
|||||||
const found = movers().find(({ options }) => options.id === owner);
|
const found = movers().find(({ options }) => options.id === owner);
|
||||||
if (!found) return true;
|
if (!found) return true;
|
||||||
const { options, store, pickRadiusPx } = found;
|
const { options, store, pickRadiusPx } = found;
|
||||||
|
if (instance < 0 || instance >= store.count || store.shows[instance] !== 1)
|
||||||
|
return false;
|
||||||
const modelRadius =
|
const modelRadius =
|
||||||
options.kind === 'model' ? (pickRadiusPx?.(instance) ?? null) : null;
|
options.kind === 'model' ? (pickRadiusPx?.(instance) ?? null) : null;
|
||||||
if (options.kind === 'model' && modelRadius == null) return true;
|
if (options.kind === 'model' && modelRadius == null) return true;
|
||||||
if (instance >= store.count) return false;
|
|
||||||
geo.cartesian3.fromElements(
|
geo.cartesian3.fromElements(
|
||||||
store.positions[instance * 3],
|
store.positions[instance * 3],
|
||||||
store.positions[instance * 3 + 1],
|
store.positions[instance * 3 + 1],
|
||||||
|
|||||||
@@ -411,3 +411,26 @@ test('a model hit is checked against its projected position within its drawn rad
|
|||||||
assert.equal(picking.drillPick({ x: 121, y: 100 })[0]?.id, 'jet');
|
assert.equal(picking.drillPick({ x: 121, y: 100 })[0]?.id, 'jet');
|
||||||
assert.equal(picking.drillPick({ x: 125, y: 100 }).length, 0);
|
assert.equal(picking.drillPick({ x: 125, y: 100 }).length, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('stale GPU model hits cannot select hidden or removed instances', async () => {
|
||||||
|
const view = fakeView();
|
||||||
|
const model = modelSet('models', [[100, 100, 50, 'jet']], null);
|
||||||
|
const picking = createNavaraPicking({
|
||||||
|
view,
|
||||||
|
projector,
|
||||||
|
camera,
|
||||||
|
movers: () => [model],
|
||||||
|
lines: () => [],
|
||||||
|
resolveBatch: () => ({ set: 'models', instance: 0, pickId: 'jet' }),
|
||||||
|
...timers(),
|
||||||
|
});
|
||||||
|
model.store.set(0, { show: false });
|
||||||
|
const hidden = picking.clickPick({ x: 100, y: 100 });
|
||||||
|
view.emit('featureClick', { batchId: 1 });
|
||||||
|
assert.equal(await hidden, undefined);
|
||||||
|
model.store.setCount(0);
|
||||||
|
const removed = picking.clickPick({ x: 100, y: 100 });
|
||||||
|
view.emit('featureClick', { batchId: 1 });
|
||||||
|
assert.equal(await removed, undefined);
|
||||||
|
picking.destroy();
|
||||||
|
});
|
||||||
@@ -83,7 +83,6 @@ export function createMoverBank(engine, { options, write, onCommit }) {
|
|||||||
capacity = wanted;
|
capacity = wanted;
|
||||||
handles.forEach((handle, index) => write(handle, set, index));
|
handles.forEach((handle, index) => write(handle, set, index));
|
||||||
set.setCount(visible ? handles.length : 0);
|
set.setCount(visible ? handles.length : 0);
|
||||||
dirty = true;
|
|
||||||
};
|
};
|
||||||
const bank = {
|
const bank = {
|
||||||
handles,
|
handles,
|
||||||
|
|||||||
@@ -286,3 +286,48 @@ test('vessels on the Navara renderer: one always-on-top chevron bank, MMSI picks
|
|||||||
globalThis.document = previousDocument;
|
globalThis.document = previousDocument;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('a vessel bank commits rows arriving after its empty visibility commit and after growth', async () => {
|
||||||
|
const { createMoverBank } = await import('../aircraft/render/navara.js');
|
||||||
|
let commits = 0;
|
||||||
|
let pending = null;
|
||||||
|
const bank = createMoverBank(
|
||||||
|
{
|
||||||
|
movers: {
|
||||||
|
createSet: () => ({
|
||||||
|
set() {},
|
||||||
|
setCount() {},
|
||||||
|
destroy() {},
|
||||||
|
commit() {
|
||||||
|
commits++;
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
options: (capacity) => ({ capacity }),
|
||||||
|
write() {},
|
||||||
|
onCommit: (next) => {
|
||||||
|
pending = next;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const flush = () => {
|
||||||
|
const next = pending;
|
||||||
|
pending = null;
|
||||||
|
next?.commit();
|
||||||
|
};
|
||||||
|
bank.setVisible(true);
|
||||||
|
flush();
|
||||||
|
bank.add({});
|
||||||
|
assert.equal(pending, bank, 'first rows schedule their GPU upload');
|
||||||
|
flush();
|
||||||
|
assert.equal(commits, 1);
|
||||||
|
for (let i = 1; i < 1024; i++) bank.add({});
|
||||||
|
flush();
|
||||||
|
bank.add({});
|
||||||
|
assert.equal(pending, bank, 'capacity growth schedules its GPU upload');
|
||||||
|
flush();
|
||||||
|
assert.equal(commits, 3);
|
||||||
|
bank.destroy();
|
||||||
|
});
|
||||||
@@ -264,6 +264,7 @@ export class StyleManager extends ShellFacade {
|
|||||||
|
|
||||||
this._layerBindings = new LayerBindings({
|
this._layerBindings = new LayerBindings({
|
||||||
viewer,
|
viewer,
|
||||||
|
engine,
|
||||||
services: {
|
services: {
|
||||||
imageryHost: () =>
|
imageryHost: () =>
|
||||||
resolveImageryHost({
|
resolveImageryHost({
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { registerNavigationAuthorityListener } from '../navigationPolicy.js';
|
|||||||
export class LayerBindings {
|
export class LayerBindings {
|
||||||
constructor({
|
constructor({
|
||||||
viewer,
|
viewer,
|
||||||
|
engine,
|
||||||
services,
|
services,
|
||||||
readControls,
|
readControls,
|
||||||
operations,
|
operations,
|
||||||
@@ -23,6 +24,7 @@ export class LayerBindings {
|
|||||||
this,
|
this,
|
||||||
{
|
{
|
||||||
viewer,
|
viewer,
|
||||||
|
engine,
|
||||||
services,
|
services,
|
||||||
readControls,
|
readControls,
|
||||||
_feedback: feedback,
|
_feedback: feedback,
|
||||||
@@ -71,7 +73,7 @@ export class LayerBindings {
|
|||||||
routeWorldFocusRequest(
|
routeWorldFocusRequest(
|
||||||
event,
|
event,
|
||||||
(detail, fly) => this._runExplicitWorldFocus(detail, fly),
|
(detail, fly) => this._runExplicitWorldFocus(detail, fly),
|
||||||
(detail) => flyToWorldTarget(this.viewer, detail),
|
(detail) => flyToWorldTarget(this.engine ?? this.viewer, detail),
|
||||||
);
|
);
|
||||||
this._removeWorldRequestFocusListener = registerWorldFocusRequestListener(
|
this._removeWorldRequestFocusListener = registerWorldFocusRequestListener(
|
||||||
window,
|
window,
|
||||||
|
|||||||
@@ -152,3 +152,21 @@ test('weather shell supplies live imagery hosts to wind and observations and rel
|
|||||||
owner.disconnect();
|
owner.disconnect();
|
||||||
for (const id of ids) assert.equal(attached.get(id), null);
|
for (const id of ids) assert.equal(attached.get(id), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test('world focus uses the engine when the shell has no Cesium viewer', async (t) => {
|
||||||
|
const { requestWorldFocus } = await import('../worldFocus.js');
|
||||||
|
replaceWindow(t, new EventTarget());
|
||||||
|
const engine = createFakeEngine();
|
||||||
|
let target;
|
||||||
|
engine.camera.flyToSphere = (sphere) => { target = sphere.center; };
|
||||||
|
const owner = new LayerBindings({
|
||||||
|
viewer: null, engine, services: {}, readControls: () => ({}),
|
||||||
|
operations: { _runExplicitWorldFocus: (_detail, fly) => fly() },
|
||||||
|
});
|
||||||
|
owner.observeCamera();
|
||||||
|
const position = { x: 6378137, y: 0, z: 0 };
|
||||||
|
requestWorldFocus({ kind: 'vessel', id: '111', position });
|
||||||
|
assert.deepEqual(target, position);
|
||||||
|
owner.stop();
|
||||||
|
});
|
||||||
Reference in new issue
Block a user