simplify defended territory rendering logic

Replace epoch-based defended texture tracking with hard-clear approach for
improved reliability and performance. Remove complex dirty state tracking
and epoch incrementing logic in favor of direct hard clears before rebuilds.

Changes:
- Remove wasDefensePostsDirty tracking from TerritoryRenderer
- Replace numUpdates > 0 checks with hasStateUpdates boolean
- Hard-clear defended texture before restamping instead of epoch management
- Mark DefendedUpdatePass as dirty when rebuilding defended state
- Rebuild bind group in DefendedUpdatePass when missing, not just on buffer change

This eliminates potential transient mismatches where defended rendering
disappeared between rebuilds and simplifies the update pipeline.
This commit is contained in:
scamiv
2026-01-17 22:49:20 +01:00
parent 21578b3ca0
commit 658d4fdfe4
2 changed files with 13 additions and 18 deletions
+12 -17
View File
@@ -316,18 +316,16 @@ export class TerritoryRenderer {
// Upload palette if needed
this.resources.uploadPalette();
// Upload defense posts if needed (tracks if it was dirty before upload)
const wasDefensePostsDirty = (this.resources as any)
.needsDefensePostsUpload;
// Upload defense posts if needed
this.resources.uploadDefensePosts();
// Initial state upload
this.resources.uploadState();
// Check if we need to run compute passes
const numUpdates = this.stateUpdatePass
? ((this.stateUpdatePass as any).pendingTiles?.size ?? 0)
: 0;
const hasStateUpdates = this.stateUpdatePass
? this.stateUpdatePass.needsUpdate()
: false;
const needsTerrainCompute = this.terrainComputePass
? this.terrainComputePass.needsUpdate()
: false;
@@ -341,14 +339,13 @@ export class TerritoryRenderer {
// Use explicit boolean checks to satisfy linter (|| is correct for boolean OR)
const shouldRebuildDefended =
this.needsDefendedRebuild === true ||
wasDefensePostsDirty === true ||
rangeChanged === true ||
countChanged === true ||
(hasPosts && numUpdates > 0);
(hasPosts && hasStateUpdates === true);
const needsCompute =
needsTerrainCompute === true ||
numUpdates > 0 ||
hasStateUpdates === true ||
shouldRebuildDefended === true ||
this.needsDefendedHardClear === true;
@@ -366,15 +363,13 @@ export class TerritoryRenderer {
// Handle defended rebuild (before executing passes)
if (shouldRebuildDefended) {
// Increment epoch for this rebuild
const epochBefore = this.resources.getDefendedEpoch();
this.resources.incrementDefendedEpoch();
const epochAfter = this.resources.getDefendedEpoch();
// Hard-clear defended texture before restamping. This avoids relying on
// epoch-stamping for correctness and prevents transient mismatches where
// defended rendering disappears between rebuilds.
this.needsDefendedHardClear = true;
// If epoch wrapped, we need a hard clear
if (epochAfter === 0 || epochAfter < epochBefore) {
this.needsDefendedHardClear = true;
this.resources.incrementDefendedEpoch();
if (this.defendedUpdatePass) {
this.defendedUpdatePass.markDirty();
}
this.needsDefendedRebuild = false;
@@ -87,7 +87,7 @@ export class DefendedUpdatePass implements ComputePass {
const oldBuffer = this.resources?.defensePostsBuffer;
const bufferChanged = oldBuffer !== resources.defensePostsBuffer;
if (bufferChanged) {
if (bufferChanged || !this.bindGroup) {
this.rebuildBindGroup();
}