mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
fix(street-level): retry lines a partial terrain lookup left draped
A tile whose terrain lookup cast some lines kept castRequested set, so a later refresh skipped it and the lines that failed stayed draped over trees and roofs until the tile was rebuilt. A refresh now retries any tile with lines still draped, and redraws it only when more of its lines can be cast, so a tile that cannot be cast fully costs a cache check, not a rebuild, per refresh. castRequested still stops the redraw from casting again at once. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
7f01f16d41
commit
4cf6920e65
2 files changed
+75
-11
No files matched your search
@@ -216,12 +216,14 @@ export function createCoverage({ state, source }) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the terrain heights a tile's lines need, then redraw it cast. A
|
||||
* cast that resolves nothing clears `castRequested`, so the next refresh
|
||||
* retries instead of this looping.
|
||||
* Fetch the terrain heights a tile's lines need, then redraw it cast.
|
||||
* `castRequested` stops the redraw from casting again at once; a refresh
|
||||
* `retry`s a tile whose lines are still draped (a failed or partial cast),
|
||||
* and it is redrawn only when more of its lines can be cast.
|
||||
*/
|
||||
function castTile(entry) {
|
||||
if (entry.castRequested || entry.castAbort || !terrainMode()) return;
|
||||
function castTile(entry, { retry = false } = {}) {
|
||||
if ((entry.castRequested && !retry) || entry.castAbort || !terrainMode())
|
||||
return;
|
||||
entry.castRequested = true;
|
||||
entry.castAbort = new AbortController();
|
||||
const { signal } = entry.castAbort;
|
||||
@@ -233,9 +235,13 @@ export function createCoverage({ state, source }) {
|
||||
if (entry.castAbort?.signal === signal) entry.castAbort = null;
|
||||
const attached = [...state.coverage.tiles.values()].includes(entry);
|
||||
if (signal.aborted || !attached || !terrainMode()) return;
|
||||
// Nothing new to cast: keep it draped until the next refresh.
|
||||
if (!lines.some((coords) => caster.castLine(coords))) {
|
||||
entry.castRequested = false;
|
||||
// Nothing new to cast: keep what is drawn until the next refresh.
|
||||
// Counted like buildSequencePrimitives: a cast line needs two points.
|
||||
const castable = lines.filter(
|
||||
(coords) => caster.castLine(coords)?.length >= 6,
|
||||
).length;
|
||||
if (castable <= (entry.castLines || 0)) {
|
||||
entry.castRequested = (entry.castLines || 0) > 0;
|
||||
return;
|
||||
}
|
||||
// A remesh may have cleared the flag while this was in flight.
|
||||
@@ -718,11 +724,12 @@ export function createCoverage({ state, source }) {
|
||||
for (const tile of tiles) loadTile(tile, kind);
|
||||
if (!state.coverage.pending.size) purgeStale();
|
||||
// The camera moved: cells that were out of the sampler's range may not be,
|
||||
// and a tile left draped by a failed or dropped cast gets another try.
|
||||
// and lines left draped by a failed, partial or dropped cast get another try.
|
||||
if (terrainMode())
|
||||
for (const entry of state.coverage.tiles.values())
|
||||
for (const entry of state.coverage.tiles.values()) {
|
||||
if (entry.castRequested) requestMesh(entry);
|
||||
else if (entry.drapedLines) castTile(entry);
|
||||
if (entry.drapedLines) castTile(entry, { retry: true });
|
||||
}
|
||||
notify();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user