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(` Engine : ${ENGINE ?? 'viewer (Cesium)'}`);
|
||||
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`);
|
||||
for (const line of vesselCardProvenanceLines(DATA_MODE)) console.log(` ${line}`);
|
||||
console.log('');
|
||||
@@ -238,7 +238,7 @@ async function main() {
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
...(!HEADFUL ? ['--use-gl=angle', '--use-angle=swiftshader'] : []),
|
||||
'--use-angle=metal',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-background-timer-throttling',
|
||||
'--disable-renderer-backgrounding',
|
||||
|
||||
@@ -223,7 +223,7 @@ async function main() {
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
'--use-gl=angle',
|
||||
'--use-angle=swiftshader',
|
||||
'--use-angle=metal',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-background-timer-throttling',
|
||||
'--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', () => {
|
||||
assert.match(ui, /registerWorldFocusRequestListener\(\s*window,/);
|
||||
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 = null;/);
|
||||
});
|
||||
|
||||
@@ -196,10 +196,11 @@ export function createCpuPicker({ projector, camera, movers, lines }) {
|
||||
const found = movers().find(({ options }) => options.id === owner);
|
||||
if (!found) return true;
|
||||
const { options, store, pickRadiusPx } = found;
|
||||
if (instance < 0 || instance >= store.count || store.shows[instance] !== 1)
|
||||
return false;
|
||||
const modelRadius =
|
||||
options.kind === 'model' ? (pickRadiusPx?.(instance) ?? null) : null;
|
||||
if (options.kind === 'model' && modelRadius == null) return true;
|
||||
if (instance >= store.count) return false;
|
||||
geo.cartesian3.fromElements(
|
||||
store.positions[instance * 3],
|
||||
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: 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;
|
||||
handles.forEach((handle, index) => write(handle, set, index));
|
||||
set.setCount(visible ? handles.length : 0);
|
||||
dirty = true;
|
||||
};
|
||||
const bank = {
|
||||
handles,
|
||||
|
||||
@@ -286,3 +286,48 @@ test('vessels on the Navara renderer: one always-on-top chevron bank, MMSI picks
|
||||
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({
|
||||
viewer,
|
||||
engine,
|
||||
services: {
|
||||
imageryHost: () =>
|
||||
resolveImageryHost({
|
||||
|
||||
@@ -13,6 +13,7 @@ import { registerNavigationAuthorityListener } from '../navigationPolicy.js';
|
||||
export class LayerBindings {
|
||||
constructor({
|
||||
viewer,
|
||||
engine,
|
||||
services,
|
||||
readControls,
|
||||
operations,
|
||||
@@ -23,6 +24,7 @@ export class LayerBindings {
|
||||
this,
|
||||
{
|
||||
viewer,
|
||||
engine,
|
||||
services,
|
||||
readControls,
|
||||
_feedback: feedback,
|
||||
@@ -71,7 +73,7 @@ export class LayerBindings {
|
||||
routeWorldFocusRequest(
|
||||
event,
|
||||
(detail, fly) => this._runExplicitWorldFocus(detail, fly),
|
||||
(detail) => flyToWorldTarget(this.viewer, detail),
|
||||
(detail) => flyToWorldTarget(this.engine ?? this.viewer, detail),
|
||||
);
|
||||
this._removeWorldRequestFocusListener = registerWorldFocusRequestListener(
|
||||
window,
|
||||
|
||||
@@ -152,3 +152,21 @@ test('weather shell supplies live imagery hosts to wind and observations and rel
|
||||
owner.disconnect();
|
||||
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