neurodoom
Deterministic pure-Rust Doom engine with per-pixel semantic and depth perception buffers for AI and multi-agent work.
#![no_std]core (usesalloc), headless by default, 320x200 output.- Classic single-player reproduction in
ClassicDoomRules. - Generic over any
GameRulesimplementation for custom multiplayer or training setups.
History
Started as a thin wrapper around PureDOOM
(a single-header, dependency-free C port of Doom). The plan was to bind
the C engine and hang perception buffers off it. In practice, almost
every subsystem — WAD parser, map loader, BSP + column rasterizer,
visplanes, sprite system, physics, state machine, sector specials, game
loop — got rewritten in pure Rust so the engine could be #![no_std],
panic-averse, and deterministic.
At a glance
use ;
let wad = read?;
let mut engine = new?;
engine.tick_single;
let rgba = engine.framebuffer; // 320 * 200 * 4 bytes
let semantic = engine.semantic_buffer; // 1 SemanticClass per pixel
let depth = engine.depth_buffer; // fixed-point distance per pixel
Examples
All three examples need a Doom WAD. Point DOOM_WAD at one, or place
doom1.wad in the project root.
# Playable single-player with level progression across the episode.
# 24 reactive bots in a 6x4 grid, fighting in E1M1 with no monsters.
# Each cell shows the bot's POV with HUD + animated weapon. Dead cells
# switch to depth view.
# Play back the recorded DEMO1 / DEMO2 / DEMO3 lumps from the WAD —
# no user input, just feeds the stored tic-commands to the engine.
Controls are documented in each example's file header.
Multi-peer rendering
DoomEngine::tick(...) is the single-player convenience — it runs
simulation for one tick and renders PeerId(0)'s view. For multi-peer
work (several AI bots sharing one world, each needing its own view),
split the two:
engine.simulate; // advance sim, no render
for peer in peers
See examples/ai_multiplayer.rs for the full pattern (including
staggered rendering to amortize the per-peer cost).
Further reading
Module-level docs (cargo doc --open) cover each subsystem. The crate
is panic-averse by design: direct panic sites are surfaced as clippy
warnings and Cargo.toml sets panic = "abort" on both dev and
release. See src/render/mod.rs for the policy details.
License
BSD-3-Clause. See LICENSE.