Daily Dev Update: Determinism, Gold Sync, and Colder Ice — September 9, 2025
Period: September 9, 2025
Total Commits: 26
Hey, here’s what we worked on today. The focus was making PvP results consistent across clients, getting the economy in sync for level-ups, cleaning up the end-game HUD, and hardening the backend so reconnects and long games are stable.
What’s New
-
Level-up flow is now consistent and fair
- Gold spends are applied in the simulation (not just UI), and the level-up button correctly disables when you’re short on gold
- This removes edge cases where the UI let you click but the sim disagreed
- [screenshot: level-up button disabled when short on gold at 72a6686]
-
Early-game ice tower tuning
- Ice Tower Level 1 damage increased from 20 to 30
- Goal: give defensive openings a bit more teeth against early minion trickles without snowballing too hard mid-game
- [screenshot: ice tower L1 buff in early-wave skirmish at 3ccef2f]
-
Cleaner end-game screen
- Removed a duplicate overlay and fixed winner reporting so it actually shows the correct winning team
- [screenshot: cleaner end-game HUD showing correct winner at 3ccef2f]
What Got Fixed
Gameplay and UI
- Fixed gold not being deducted when purchasing levels
- Added the missing newLevel field to the purchase action so the sim and UI stay in lockstep
- Level-up button now reads fresh sim values instead of stale React state
- Reverted a projectile speed change that caused weirdness—projectiles should feel normal again
- Corrected GameHUD logic to capture and display the actual winning team
Bots and Practice Matches
- Bots now detect castle destruction and properly end the game
- Fixed minion spawn targeting (string-to-enum conversion issue)
- Gold calculation for bots matches the client again
- Added an event dispatcher for castle damage/destruction so bots react to state changes instead of polling
Determinism and Sync
- Pathfinding now uses Manhattan normalization to avoid float math and keep results deterministic across machines
- Swapped out floating-point square roots for integer arithmetic throughout the sim
- Fixed a sim loop crash from a bad method reference and tightened history processing during resync
- Renderer now pauses and resumes cleanly during history catchup to prevent double-updates
- Replays and reconnects should be more reliable under load
[screenshot: smoother tower attack animation timing at 9b19976]
Networking and Stability
- WebSockets through the load balancer are now tuned for long sessions
- Idle timeout 3600s, sticky sessions enabled, both websocket and polling transports, longer ping timeout, and deflate disabled for proxy compatibility
- HTTPS is on by default via the load balancer with automatic redirect from HTTP
- CORS configured to allow production domains so clients don’t get blocked
- Fixed a bunch of service binding issues (explicit IPv4, correct ports, health checks that actually pass)
Build, Deploy, and Runtime
- Workers start correctly in production with the right NODE_ENV and file paths
- Simplified module resolution with tsx/tsconfig-paths so monorepo imports work in prod
- Cleaned up circular stack dependencies in infra to allow safe instance replacements
- Ensured our Graviton/ARM64 instances use the right agent binaries and reliably roll on user-data changes
- Wiki deploy path fixed so docs publish again
- Added noisy logging while we traced worker lifecycle issues, then removed the spam once things were stable
What’s Still Broken (or a bit wobbly)
- Projectile physics just got reverted to a safer path; we’re watching for stray speed inconsistencies in edge cases
- Resyncs are better, but you might still see a brief stutter when reconnecting to a long match
- Manhattan normalization slightly changes minion micro around corners; we’ll adjust speed/feel if it messes with known route timings
- Dev HMR is disabled for stability. It’s on purpose for now while we chase determinism
Under the Hood
- Full integer math in the sim to keep cross-client results identical
- Event-driven game state changes so bots and UI respond to the same ground truth
- Clearer separation between simulation and rendering to prevent timing drift
- Better logging across the board (bots, server, reconnection paths) to track bad states quickly
- Infrastructure hardening: SSL, proper security group rules, ALB stickiness/timeouts, IPv4 binding, consistent ports, and automated instance replacements
What’s Next
- Finish the determinism pass on projectile and collision timing
- Keep tuning early-game defense (follow-up levels on ice and counters)
- More work on reconnect smoothness and replay robustness
- Begin wiring up the next round of PvP balance passes with tower synergies in mind
Thanks for the reports and replays—those are helping us pin down the last sync gremlins. If you spot inconsistent outcomes between clients or odd pathing choices, send us a timestamp and match context and we’ll dig in.