feat: render server-generated terrain - #6
Closed
JJiang28 wants to merge 1 commit into
Closed
Conversation
The map drew one grass texture for every visible tile and fog for the rest, because the server had no terrain to describe. It does now, so fetch the planes once via MapService.GetTerrain and render them. Split tiles.ts, which baked each building into its own opaque tile texture and so could only ever draw a farm on grass — on desert it carried a patch of grassland with it. Ground, relief, vegetation, rivers, resources and buildings are now separate sprites composited per tile, so a structure sits on whatever ground it occupies. Terrain outside vision is desaturated rather than blacked out. Nothing leaks: the server filters entities by vision, so a fogged tile has no city or building to reveal, and a coastline is not worth hiding. All layers deliberately share one texture geometry and therefore one anchor. Per-layer heights would save about 0.4MB but each needs its own anchor derived from its own CY/TEX_H; get one wrong and that layer sits ~26px off while still looking almost right. Worse, hit-testing is pure math via pixelToHex and stays correct only while a sprite sits at exactly hexToPixel(col, row), so "fixing" such an offset by nudging sprite.y would silently desync clicks from what is drawn. Enums come from the generated proto rather than a hand-written copy, so the byte values packed into each plane have one definition. Also corrects the gameConfig defaults, which claimed a 128-wide map and a vision radius of 5 against a server serving 75 and 3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MapService.GetTerrainand renders ground, relief, vegetation, rivers and special resources as separate composited sprites. Previously every visible tile drew one grass texture and everything else drew fog.tiles.ts, which baked each building into its own opaque tile texture and so could only ever draw a farm on grass — on desert it carried a patch of grassland with it. Buildings are now transparent sprites over whatever ground they occupy.gameConfigdefaults, which claimed a 128-wide map and a vision radius of 5 against a server serving 75 and 3.Notes for reviewers
All layers share one texture geometry and therefore one anchor, deliberately. Per-layer heights would save ~0.4 MB, but each then needs its own anchor derived from its own
CY / TEX_H; get one wrong and that layer sits ~26 px off while still looking almost right. Worse, hit-testing is pure math viapixelToHexand stays correct only while a sprite sits at exactlyhexToPixel(col, row)— so "fixing" such an offset by nudgingsprite.ywould silently desync clicks from what is drawn. One geometry makes that unrepresentable.Terrain outside vision is desaturated rather than blacked out. Nothing leaks: the server already filters entities by vision, so a fogged tile has no city or building to reveal.
getVisDiststays on Chebyshev distance on purpose — it mirrorsdomain.PointVisibleserver-side, and switching the client to true hex distance would make the fog ring disagree with which entities actually arrive.Depends on city-io/backend#13, which adds
GetTerrain. Merge that and deploy it first, or this build has no terrain to fetch.proto/here mirrors only the terrain additions. The army protos from backend #12 are not yet mirrored into this repo; that sync belongs with the armies frontend work rather than being smuggled in here.Known follow-up
The renderer still tears down and rebuilds every visible tile on each ~3 s stream tick, and never frees tiles panned past. That predates this change, but terrain multiplies per-tile sprites, so the cost is now several times higher. A renderer restructure (pooling, real culling, diff updates, texture atlas) is the intended next change.
Test plan
yarn checkandyarn buildcleanyarn generatereproduces the committed generated code exactly