5.6 KiB
Executable File
5.6 KiB
Executable File
Roadmap
Workspace layout: shared/ (wire types), server/ (authoritative sim), client/ (render
terminal). The platform layer — window, GPU, input, RGB332 palette — lives in the external
pbio crate (git dependency), not in this repo.
Achieved milestones
- TGA loader:
Image,from_tga,to_tileset,decode_rleinclient/src/assets.rs - Pixel helpers:
set_pixel,extract,blit,blit_tileinclient/src/game/pixelhelper.rs— signedi32offsets, clip against all four framebuffer edges, index 0 = transparent - Input system:
GameAction,InputMap,InputStateinclient/src/input.rs(overpbio::Key) - Protocol spec:
notes/protocol.md— Header, State, Action, Chunk, Entity, EntityQuery, EntityDetail, Ping/Pong; reliability model - Shared crate: packet structs as
bytemuck::Podwith compile-time size assertions,player_action/packet_typeconstants,chunk_id/chunk_coords - Server binary: 24 Hz tick loop, 3×3-chunk test world (
build_world), wall collision, per-client action queue,ChunkPacketdispatch on cache miss, stale-client eviction - Client net:
NetClientinclient/src/net.rs, non-blocking UDP recv,StatePacket/EntityPacket/ChunkPacket/PongPacketdispatch, entity-checksum retransmit - End-to-end loop: player moves on server, position reflected in
EntityPacket, rendered on client - Tile rendering: chunk-based world rendering from received
ChunkPacketdata (6-bit unpack) - Tick-based movement: movement resolved in
entity_tick, currently every 4th tick (sim.rs) - Sprite-based entity rendering: entity
type_id→ tile inentities.tga, blitted with transparency - Phase-staggered broadcast: per-client
send_phase, flat outbound load across ticks - Ping/Pong RTT measurement (
PingPacket/PongPacket) - Connection timeout: client emits
Disconnectedafter 10 s without aStatePacket; server evicts clients unseen for 10 s
Upcoming work
06 — Hybrid tick loop (partially done)
Design of record: notes/06-hybrid-tick-loop.md (24 Hz base tick + stride scheduling).
This supersedes the original 20/10/1 Hz three-tier sketch.
- 24 Hz base loop (
server/src/main.rs) - Phase-staggered broadcast at 12 Hz/client (
send_phaseinserver/src/net.rs) - Stride layout settled:
entity_tickat%4(6 Hz, sets movement rate), broadcast at%2(12 Hz/client). The06note now documents this and why. - Action-point model (
energy/speedper entity, act whenenergy >= ACTION_COST). Removed fromentity.rsfor now as premature — reintroduce when NPCs (08) actually need it. Thenentity_tickcan move to%2(12 Hz) andspeedsets the effective movement rate.
07 — Tiled map loader
Replace the hardcoded build_world wall loop with real level data.
- Parse Tiled TMX (XML) or JSON export — only the subset actually used
- Define the tile vocabulary:
TileKindvariants map 1:1 to Tiled tile IDs - Load a hand-authored starting area as the first real level
- Procedural generation comes later; hand-authored first
08 — Basic NPC entity + AI budget
One dumb wandering enemy. Validates the simulation architecture before complexity accumulates. Depends on the action-point model from 06 being reintroduced.
- Add
EntityKind::Npcwith athink() -> u32method returning budget cost - Per sim-tick: distribute
think_budget = BASE / (clients + 1)across entities ordered by player proximity - Complex entities consume more budget; simple ones less. Loop breaks at zero — natural load shedding.
- No framework. No trait objects yet. A match on
EntityKindis fine.
let mut budget: u32 = BASE_BUDGET / (client_count + 1).max(1);
for entity in entities_by_player_proximity() {
if budget == 0 { break; }
budget = budget.saturating_sub(entity.think(&mut world));
}
09 — Client camera (sprite rendering already done)
Sprite rendering already landed (see Achieved). What remains is the camera:
- Smooth camera: lerp between last known and current server position; do not snap
(currently
player_possnaps hard to the server position ingame.rs) - Store previous + current position per entity, interpolate on render
- Camera math is architectural — affects how entity state is stored. Do it before UI.
Later — UI / HUD
- Bitmap font renderer: 8×8 glyph sheet TGA,
draw_text(frame, font, x, y, color, text)— seenotes/04 - UI primitives in
client/src/ui.rs:fill_rect,draw_rect,draw_hbar— seenotes/05 - HUD layout (320×240): HP bar + player name bottom 16px, message log right panel
- A real clip-rect on the blit primitives belongs here — once the viewport and HUD panels are two distinct regions, the abstraction earns its keep. Not before.
Later — Robustness + auth
- Auth token handshake: replace source-address identity (
auth_tokenfield exists but is unused) - Multi-datagram
EntityPacket: server currently truncates at 66 entities (net.rsTODO) - Asset embedding:
include_bytes!for single-binary distribution
Later — World depth
Once the simulation architecture is stable and a real level exists:
- Doors, interactive objects (server-authoritative state)
- Combat: melee range check, HP, death, respawn
- Inventory: on-demand via
EntityQueryPacket/EntityDetailPacket - Day/night and weather on the slow tick — affect visibility, spawns
- Procedural dungeon generation (BSP or cellular automata feeding into the same tile format)