Skip to content

Fix the connected tile drawer's timeout unit mismatch#323

Open
NayiemW wants to merge 1 commit into
CnCNet:masterfrom
the-real-antares:fix-connected-tile-drawer-timeout
Open

Fix the connected tile drawer's timeout unit mismatch#323
NayiemW wants to merge 1 commit into
CnCNet:masterfrom
the-real-antares:fix-connected-tile-drawer-timeout

Conversation

@NayiemW

@NayiemW NayiemW commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

When drawing cliffs or shorelines, WAE runs an A* pathfinding search to determine the connected tile sequence between the selected start and end points.

Because the search space can become large, the pathfinder uses a watchdog: if the search makes no progress within the configured timeout, it aborts and places the best partial path found so far.

The timeout was calculated as:

timeout = Stopwatch.GetTimestamp() + TimeSpan.FromMilliseconds(10).Ticks;

This mixes two incompatible clock units:

  • TimeSpan.Ticks always uses 100-nanosecond units, so 10 ms equals 100,000 ticks on every platform.
  • Stopwatch.GetTimestamp() uses Stopwatch.Frequency, which is platform-dependent.

On Windows, the high-resolution counter commonly runs at 10 MHz, meaning one timestamp unit equals 100 nanoseconds. The units therefore happen to match, and the timeout behaves as intended.

On the browser’s .NET runtime, as well as on Linux and macOS, Stopwatch.Frequency is typically 1 GHz, meaning one timestamp unit equals one nanosecond. In that environment, adding 100,000 TimeSpan ticks produces a timeout of only 0.1 ms instead of 10 ms.

As a result, the watchdog fires approximately 100 times too early. The A* search aborts almost immediately and WAE places an incomplete tile path, which matches the broken cliffs shown in Rampastring’s screenshot.

The suspicion that the browser was hitting the performance cap sooner was correct, but the underlying issue was more severe: the timeout was accidentally 100 times shorter on every affected platform.

The fix calculates the deadline using the stopwatch’s actual frequency:

timeout = Stopwatch.GetTimestamp()
    + Stopwatch.Frequency / 1000 * timeoutMilliseconds;

This produces the correct duration on every platform.

The browser build is also given a more generous 100 ms budget because pathfinding is slower under the interpreted runtime. This watchdog resets whenever progress is made, so the increased timeout does not delay normal searches; it only gives genuinely slow or stalled searches more time before aborting.

This is not strictly a browser-specific fix. Any future Linux or macOS desktop build of WAE would otherwise suffer from the same broken autotiling behavior.

PR formatted with AI tools

The pathfinding stall watchdog added TimeSpan ticks, which are fixed 100-nanosecond units, to Stopwatch timestamps, which use platform-specific Stopwatch.Frequency units. The two only coincide on Windows, where the query performance counter runs at 10 MHz. In the browser the runtime reports timestamps in nanoseconds, shrinking the intended 10 millisecond budget to 0.1 milliseconds, so the search aborted early and placed partial connected tile paths. Convert the budget through Stopwatch.Frequency, and give the browser a larger budget to compensate for the interpreted runtime's higher per-node cost and coarser timer granularity.
@NayiemW NayiemW force-pushed the fix-connected-tile-drawer-timeout branch from b31f156 to 053dae3 Compare July 10, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant