mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
Let a view show an aircraft's cockpit view
A view's follow may ask for cockpit view, which the app enters after it follows the aircraft; links cannot carry it and open the app following. Applying a view no longer flies the camera when the followed entity is already there, since the flight ended the follow; it flies only while waiting for the entity. The panel applies its first view again only when it asks for cockpit view.
This commit is contained in:
1 parent
89a448ee83
commit
d4311a9d54
6 files changed
+77
-25
No files matched your search
+29
-18
@@ -185,25 +185,36 @@ export async function applyView(
|
||||
await act('clear_annotations', {});
|
||||
if (view.annotations.length)
|
||||
await act('annotate_map', { annotations: [...view.annotations] });
|
||||
steps.push({ step: 'camera', ok: await flyTo(viewer, view.camera) });
|
||||
if (view.follow) {
|
||||
// The followed entity appears once its layer has data; retry until then.
|
||||
const args = {
|
||||
query: view.follow.id,
|
||||
layerId: FOLLOW_LAYERS[view.follow.kind],
|
||||
};
|
||||
let followed = false;
|
||||
for (let attempt = 0; attempt < FOLLOW_ATTEMPTS && !followed; attempt++) {
|
||||
if (signal?.aborted) break;
|
||||
try {
|
||||
followed = (await run('track_entity', args))?.ok === true;
|
||||
} catch {
|
||||
followed = false;
|
||||
}
|
||||
if (!followed) await delay(retryMs, signal);
|
||||
}
|
||||
steps.push({ step: 'follow', ok: followed });
|
||||
if (!view.follow) {
|
||||
steps.push({ step: 'camera', ok: await flyTo(viewer, view.camera) });
|
||||
return steps;
|
||||
}
|
||||
// A followed entity owns the camera, and a camera flight would end the
|
||||
// follow, so fly to the view only while the entity is not there yet. It
|
||||
// appears once its layer has data; retry until then.
|
||||
const layerId = FOLLOW_LAYERS[view.follow.kind];
|
||||
const follow = async () => {
|
||||
try {
|
||||
return (
|
||||
(await run('track_entity', { query: view.follow.id, layerId }))?.ok ===
|
||||
true
|
||||
);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let followed = await follow();
|
||||
if (!followed) {
|
||||
steps.push({ step: 'camera', ok: await flyTo(viewer, view.camera) });
|
||||
for (let attempt = 1; attempt < FOLLOW_ATTEMPTS && !followed; attempt++) {
|
||||
if (signal?.aborted) break;
|
||||
await delay(retryMs, signal);
|
||||
followed = await follow();
|
||||
}
|
||||
}
|
||||
steps.push({ step: 'follow', ok: followed });
|
||||
if (followed && view.follow.cockpit)
|
||||
await act('control_cockpit', { action: 'enter', targetLayer: layerId });
|
||||
return steps;
|
||||
}
|
||||
|
||||
|
||||
@@ -283,3 +283,30 @@ test('a panel reports a render error in full and stops drawing', () => {
|
||||
console.error = original;
|
||||
}
|
||||
});
|
||||
|
||||
test('a followed aircraft owns the camera, and cockpit view is entered after it', async () => {
|
||||
const viewer = fakeViewer();
|
||||
const { calls, run } = recorder();
|
||||
const steps = await applyView(
|
||||
createView({
|
||||
camera: { lat: 32.7, lon: -117.2 },
|
||||
follow: { kind: 'military_aircraft', id: 'AE1234', cockpit: true },
|
||||
}),
|
||||
{ viewer, dataManager: fakeLayers(new Set()), run, retryMs: 0 },
|
||||
);
|
||||
// Following worked at once, so no camera flight ended it.
|
||||
assert.equal(viewer.flights.length, 0);
|
||||
assert.deepEqual(calls.slice(-2), [
|
||||
['track_entity', { query: 'ae1234', layerId: 'military' }],
|
||||
['control_cockpit', { action: 'enter', targetLayer: 'military' }],
|
||||
]);
|
||||
assert.ok(steps.every((step) => step.ok));
|
||||
assert.throws(
|
||||
() =>
|
||||
createView({
|
||||
camera: { lat: 0, lon: 0 },
|
||||
follow: { kind: 'satellite', id: '25544', cockpit: true },
|
||||
}),
|
||||
/no cockpit view/,
|
||||
);
|
||||
});
|
||||
@@ -471,8 +471,8 @@ export function panelRuntime(config) {
|
||||
location.href.split('#')[0] + new URL(url).hash,
|
||||
);
|
||||
// The app restores this view from its link, following included, so
|
||||
// it must not be applied again: flying there would end the follow.
|
||||
if (queued === view) queued = null;
|
||||
// it needs applying again only for what links cannot carry: cockpit.
|
||||
if (queued === view && !view.follow?.cockpit) queued = null;
|
||||
} catch {
|
||||
// The view still arrives once the app is ready.
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user