- Fixed spectator cell color mismatch — spectators could see a player's cells rendered with different colors after a skin loaded via login. Root cause:
server_invalidate_player_cells() only invalidated active (alive) players' view caches, never touching spectator view state (spec_view_state, center_spec_view_state). Old cells kept the no-skin appearance while new splits showed the skin, creating a two-tone visual
- Invalidation now covers all three viewer paths: individual (alive + free-roam spectators via
connected_ids), grouped spectators, and center spectators
- Also clears
view_state[] when removing cells from client_nodes, ensuring the diff engine classifies re-added cells as ADD (with full skin/name) instead of UPDATE
- Deferred view_state clearing —
server_remove_cell() no longer iterates all connected players to clear visibility state per removal. Clearing is deferred to server_alloc_cell() at reuse time. Eliminates O(connected × removed) random cache-cold writes per tick
- Single quadtree rebuild per tick — merged the two separate
server_rebuild_quadtree() calls (post-movement and post-spawn) into a single rebuild after all mutations are complete. Saves ~0.3–0.5ms per tick at 5000+ dynamic cells
- Incremental food grid — added
fg_remove() for O(1) bucket removal. Food eat/spawn now use incremental insert/remove instead of triggering a full rebuild of 4000+ entries. Full rebuild only triggers on border change (map resize)
- Ejected rigid body early-out — the ejected-vs-ejected push-apart loop now skips entirely when
moving_count == 0 (no cells in flight). Avoids scanning all dynamic_nodes on quiet ticks
- Anti-teaming system rewritten — replaced the legacy discrete event-based system (64-event array per player, 788 bytes/player) with a Delta Server-style exponential decay multiplier (single float, 8 bytes). Each teaming action bumps a multiplier; decay = base × pow(1.086, multiplier). Recovery is automatic via a compensation constant (-0.005/cycle). ~780 bytes saved per player (~800KB for 1024 players).
- New config parameters:
at_extra_decay_base, at_compensation, at_split_loss, at_eject_loss, at_virus_pop_loss, at_danger_loss
- Opcode 0xCA (202) updated to report the new multiplier value while maintaining backward-compatible wire format
- Fixed spectator #1 follow flickering — viruses and cells near the viewport edge no longer blink in and out. Root cause: the grouped spectator viewbox had no true hysteresis — the same 600px padding was used for both adding and removing cells, so natural scale/center jitter from the followed player caused edge cells to oscillate between visible/invisible every tick
- Implemented asymmetric hysteresis: cells enter visibility at 600px viewport padding but only leave at 1200px, creating a 600px dead zone that absorbs camera jitter
- Added EMA smoothing to spectator scale (15% weight per tick) to dampen per-tick fluctuations from eating, decaying, splitting, and merging
- Live server status endpoint:
GET /status returns real-time JSON with player count, spectators, uptime, and map scale
- LegendMod homepage now shows live ONLINE/OFFLINE badge with dynamic player counts fetched from the game server
- Map scale indicator: displays current map tier (1/4, 1/2, 1×, 2×, up to 8×) in real time
- Status updates run on the accept thread with lock-free volatile reads — zero impact on game loop performance
- Fixed cell flickering/blinking during spectate — MAX_QUERY_NODES increased 8× (8192→65536) to prevent non-deterministic viewport truncation
- view_state cleared on every spectate mode transition, fixing one-frame blinks from stale add/update classification
- Fixed stale leaderboard — disconnected players/bots no longer persist on the leaderboard. Server now sends an empty leaderboard packet (count=0) when all players leave
- New embed page — gaming portals can now embed Expanding Land on their websites with a simple iframe snippet
- MAX_VIEW_NODES limit (16384) prevents OOM crashes during extreme zoom-out while keeping 30× headroom for spectators
- Viewport culling now sends only visible nodes — eliminates FPS drops when zoomed out on large maps
- Conditional logout: auto-signs out when joining a private server that isn't Expanding Land, preventing opcode 102 conflicts
- Login buttons (Facebook, Google, Discord) are now disabled on unsupported server types
- Fixed cell color inconsistencies under high bot density by including name/skin data in update packets
- Cell merging logic restored and stabilized under high-density scenarios
- Player identity now consistent across cell updates (name + skin in every packet)
- Mobile touch controls: "Stop Where Finger Was" mode fully restored
- Multibox auto-spectate fix ported to TypeScript branch
- Full Map spectate button now triggers legendmod.sendAction(56) on EL servers
- Fixed game disconnects on imsolo/agar2 servers when logging in via Google or Facebook
- Login opcode 102 now conditionally skipped for legacy servers
- Encrypted WebSocket connections enforced across all server types
- Pure C server engine achieving ~5ms tick time (8× faster than Node.js)
- 720 concurrent real players per arena — zero bots
- Resizable map system: 0.25× to 8× dynamic scaling based on player count
- 200+ spectator slots with free-roam camera
- Anti-teaming system with exponential decay multiplier (Delta Server architecture)
- Ghost cells on death — see where you died
- Session stats: time alive, highest mass, food eaten, players eaten
- Full Legend Mod, Delta, and Agar2 compatibility
- Android APK support via WebView wrapper
- Discord OAuth login integration