popertots 5c4725b4a0 fix: lerp RGB toward sky colour with full opacity — no alpha fade
- tile_for_depth: alpha always 1.0, lerp RGB from white toward sky RGB
  instead of fading tile out via alpha. Tiles stay opaque.
- Expose LAYER_ALPHA as pub const so it can be tuned at runtime
- LAYER_ALPHA changed from 41/255 to 50/255 for steeper visible fade
- Invisible tiles: explicit solid sky colour, not tile_for_depth(0, 999)
2026-03-20 14:34:07 +00:00
2026-03-20 10:52:46 +00:00
2026-03-20 11:19:54 +00:00
2026-03-19 20:17:15 +00:00

Dorf

A Dwarf Fortress-inspired simulation game built in Rust with Bevy. The focus is on a fully data-oriented chunk engine: procedural terrain, hierarchical pathfinding, GPU-baked sprite rendering, and dynamic chunk loading/unloading — all designed to scale to a full DF-style world with z-levels, entities, and simulation.

This is an engine foundation, not a complete game. Many features (crafting, needs, combat, world history) exist only as stubs or are entirely absent. The chunk rendering and pathfinding systems are production-quality; the simulation layer above them is early.

Architecture

src/
├── camera.rs          # Panning camera, z-level control (Q/E, scroll)
├── config.rs          # GameConfig resource
├── constants.rs       # Tile size, pathfinding constants
├── entities/          # Dorfs, pigs, rabbits — ambulatory entities
│   ├── sentient/
│   ├── livestock/
│   └── shared_*/     # Ambulatory, pathfinding systems
├── game.rs            # ZIndex resource, frame timing
├── main.rs            # Bevy app bootstrap
└── world/
    ├── chunks/        # ChunkMap, chunk loading/unloading, connectivity
    ├── generation/    # Terrain blobs, forestry, foliage (stub), fauna (stub)
    └── tiles/        # TileMap, TileRegistry, rendering, visibility

Chunk Architecture

  • World chunks: 8×8 tiles (CHUNK_SIZE = 8, CHUNK_SIZE_TILE = 128px)
  • Render chunks: 32×32 tiles (CHUNK_TILES = 32, 512px). One render chunk = 4×4 world chunks. This mismatch is intentional — a single GPU texture covers multiple world chunks, which means chunk unloading must mark the render chunk dirty (not the world chunk).
  • Z-levels: 5 below, 15 above, 21 total (Z_BELOW = 5, Z_ABOVE = 15). Terrain is rendered as quilted sprites — one texture per z-level, all stacked in the shader.
  • Loading: setup_initial_chunks runs at Startup, emits GenerateChunkEvent for all chunks in initial_chunk_radius. handle_chunk_events processes events and fires terrain/forestry/foliage/fauna generation events.
  • Unloading: unload_chunk(chunk_pos) is the canonical function. Currently disabled — dynamic_chunk_unloading_system is a no-op stub. To enable: implement a system that diffs wanted chunks (player/NPC interest radius) against ChunkMap.loaded_chunks and calls unload_chunk for each evictable chunk.

Rendering Pipeline

  1. handle_tile_occlusion_updates — raycasts from each tile upward to compute visible_range bitmask (which z-levels can see it)
  2. build_quilted_terrain_sprites — GPU bake: tiles bucketed by (render_chunk, z_level), blitted into pooled pixel buffers, spawned as TerrainSprite entities
  3. update_tile_visibility — toggles Visibility on sprites based on current ZIndex (camera z-level)

Pathfinding

Three tiers, gated by distance:

  • Tier 1 (<4 chunks): synchronous A* on TileMap
  • Tier 2 (48 chunks): provisional path + full path via async queue
  • Tier 3 (>8 chunks): hierarchical chunk graph → async segmented A*

PathfindingBenchmark resource tracks sync vs async performance per frame.

Entity Indexing

Static terrain entities (floor tiles, fixtures, trees) are indexed in chunk_entity_index: HashMap<IVec2, Vec<Entity>> at spawn time. When a chunk unloads, the index is retrieved and entities are despawned. This is O(entities in chunk), not O(total entities).

Mobile entities (dorfs, pigs, rabbits) are not in chunk_entity_index. They are spawned once at game start and persist. They will need per-chunk lifecycle management once fauna generation is implemented.

Controls

Key Action
Click + drag Pan camera
Scroll Pan camera
Q / E Move camera z-level down / up
Mouse wheel Pan camera

Configuration

config.toml:

  • initial_chunk_radius: chunks loaded around origin at startup (default: 7 → 15×15 = 225 chunks)
  • spawn_counts: dorfs, pigs, rabbits spawned at game start

tiles.toml: tile registry — floor tiles, fixture tiles. Each tile has id, astar_weight, can_stand_in, can_stand_on, transparent flags.

Status

Implemented

  • Procedural terrain (blob-based, simplex noise heightmap)
  • Tile registry (tiles.toml) with A* weights
  • Floor tiles, fixture tiles, item tiles
  • Z-levels with quilted GPU sprite rendering
  • Tile occlusion / visibility raycasting
  • Forestry: tree trunks + leaves spawned per chunk
  • Dorfs, pigs, rabbits spawning at startup
  • Hierarchical async pathfinding (3 tiers)
  • Chunk loading infrastructure
  • Chunk unloading infrastructure (unload_chunk, dynamic_chunk_unloading_system stub)
  • Camera panning + z-level control
  • GPU texture pooling (pixel buffer reuse across bakes)
  • Render chunk dirty-tracking for incremental rebakes

Stubs (exist as empty functions, wired into schedules)

  • Foliage generation per chunk (generate_chunk_foliage)
  • Fauna spawning per chunk (generate_chunk_fauna)
  • Weathering and precipitation (generate_chunk_weathering_and_precipitation)

Not Started

  • Crafting, stockpiles, resource gathering
  • Needs, mood, stress systems
  • Job assignment and task automation
  • Building and construction (digging/mining)
  • Combat and squad management
  • Item persistence and inventory
  • Save/load world state
  • World history and procedural storytelling
  • UI (menus, z-level overlay, workshop assignment)
  • Dynamic chunk loading (player/NPC-centered, not just radius-at-startup)

Building

cargo build   # dev profile, ~1.2K warnings (pre-existing)
cargo run     # dev mode

[profile.dev.package."*"] opt-level = 3 gives near-release perf in dev builds.

S
Description
A DF inspired civ-sim RTS sandboxy thing
Readme
1.5 MiB
Languages
Rust 100%