Add ECS stuff

master
Alex Bethel 2022-01-02 12:56:42 -06:00
parent b5ddf09bb9
commit 50024fa8fa
6 changed files with 418 additions and 10 deletions

295
Cargo.lock generated
View File

@ -2,6 +2,29 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
dependencies = [
"getrandom",
"once_cell",
"version_check",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "atom"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9ff149ed9780025acfdb36862d35b28856bb693ceb451259a7164442f22fdc3"
[[package]]
name = "autocfg"
version = "1.0.1"
@ -20,15 +43,72 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-queue"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "dungeon_game"
version = "0.1.0"
dependencies = [
"float-ord",
"grid",
"lazy_static",
"pancurses",
"pathfinding",
"rand",
"specs",
"specs-derive",
]
[[package]]
@ -74,6 +154,28 @@ name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hibitset"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93a1bb8316a44459a7d14253c4d28dd7395cbd23cc04a68c46e851b8e46d64b1"
dependencies = [
"atom",
"rayon",
]
[[package]]
name = "indexmap"
@ -103,6 +205,12 @@ dependencies = [
"either",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.112"
@ -118,6 +226,27 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg",
]
[[package]]
name = "mopa"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915"
[[package]]
name = "ncurses"
version = "5.101.0"
@ -135,6 +264,16 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c"
[[package]]
name = "nom"
version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
dependencies = [
"memchr",
"version_check",
]
[[package]]
name = "num-traits"
version = "0.2.14"
@ -144,6 +283,22 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "pancurses"
version = "0.17.0"
@ -193,6 +348,24 @@ version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47aa80447ce4daf1717500037052af176af5d38cc3e571d9ec1c7353fc10c87d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.4"
@ -233,12 +406,134 @@ dependencies = [
"rand_core",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "shred"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb0210289d693217926314867c807e0b7b42f7e23c136adb31f8697f5bf242d3"
dependencies = [
"arrayvec",
"hashbrown",
"mopa",
"rayon",
"smallvec",
"tynm",
]
[[package]]
name = "shrev"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5752e017e03af9d735b4b069f53b7a7fd90fefafa04d8bd0c25581b0bff437f"
[[package]]
name = "smallvec"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
[[package]]
name = "specs"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dcc1e4ba7ab1f08ecb3d7e2f693defc3907e2c03bb0924f9978be45b364f83f"
dependencies = [
"crossbeam-queue",
"hashbrown",
"hibitset",
"log",
"rayon",
"shred",
"shrev",
"tuple_utils",
]
[[package]]
name = "specs-derive"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e23e09360f3d2190fec4222cd9e19d3158d5da948c0d1ea362df617dd103511"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tuple_utils"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44834418e2c5b16f47bedf35c28e148db099187dd5feee6367fb2525863af4f1"
[[package]]
name = "tynm"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4df2caa2dc9c3d1f7641ba981f4cd40ab229775aa7aeb834c9ab2850d50623d"
dependencies = [
"nom",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"

View File

@ -6,8 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
specs = "0.17.0"
specs-derive = "0.4.1"
lazy_static = "1"
pancurses = "0.17.0"
rand = "0.8.4"
grid = "0.6.0"
float-ord = "0.3.2"
pathfinding = "3.0.5"
pathfinding = "3"

23
src/components.rs Normal file
View File

@ -0,0 +1,23 @@
//! ECS components.
use specs::prelude::*;
use specs_derive::Component;
/// Entities that have a physical position in the world.
#[derive(Component)]
pub struct Position {
pub x: usize,
pub y: usize,
}
/// Entities that need to be drawn as a single character.
#[derive(Component)]
pub struct CharRender {
pub glyph: char,
}
/// Registers every existing component with the given ECS world.
pub fn register_all(world: &mut World) {
world.register::<Position>();
world.register::<CharRender>();
}

View File

@ -57,9 +57,6 @@ impl DungeonLevel {
win.addch(self.render_tile(x, y));
}
}
// Leave the cursor at the lower-left.
win.mv(0, 0);
}
/// Renders the tile at the given coordinates.

View File

@ -1,19 +1,36 @@
use components::{register_all, Position, CharRender};
use game::{BranchConfig, DungeonLevel};
use pancurses::{endwin, initscr};
use specs::prelude::*;
use systems::IOSystem;
mod components;
mod game;
mod rooms;
mod systems;
mod util;
fn main() {
let window = initscr();
let mut world = World::new();
register_all(&mut world);
let cfg = BranchConfig;
let level = DungeonLevel::new(&cfg);
level.draw(&window);
window.refresh();
window.getch();
world.insert(level);
endwin();
world
.create_entity()
.with(Position { x: 5, y: 6 })
.with(CharRender { glyph: '@' })
.build();
let mut dispatcher = DispatcherBuilder::new()
.with(IOSystem::new(), "render_system", &[])
.build();
loop {
dispatcher.dispatch(&mut world);
}
}

73
src/systems.rs Normal file
View File

@ -0,0 +1,73 @@
//! ECS systems.
use std::sync::Mutex;
use lazy_static::lazy_static;
use pancurses::{Window, endwin, initscr};
use specs::prelude::*;
use crate::{components::{Position, CharRender}, game::DungeonLevel};
/// System for drawing the state of the game, and potentially waiting
/// (blocking) for user input.
pub struct IOSystem {
window: Window,
}
lazy_static! {
static ref WINDOW_INITIALIZED: Mutex<bool> = Mutex::new(false);
}
impl IOSystem {
pub fn new() -> Self {
let mut init = WINDOW_INITIALIZED.lock().unwrap();
if *init {
// See the note on `impl Send for IOSystem`.
panic!("Refusing to initialize the renderer twice");
}
*init = true;
Self { window: initscr() }
}
}
impl Drop for IOSystem {
fn drop(&mut self) {
endwin();
*WINDOW_INITIALIZED.lock().unwrap() = false;
}
}
// The `Window` type from pancurses contains a raw pointer, and as a
// result Rust isn't convinced that it's safe to send between threads.
// Since we guarantee that only one `Window` object is ever created at
// a time, it is in fact safe to send the render system's data between
// threads.
unsafe impl Send for IOSystem {}
impl<'a> System<'a> for IOSystem {
type SystemData = (
ReadExpect<'a, DungeonLevel>,
ReadStorage<'a, CharRender>,
ReadStorage<'a, Position>,
);
fn run(&mut self, (level, renderables, positions): Self::SystemData) {
// Draw the base level.
level.draw(&self.window);
// Draw all renderable entities in the ECS.
for (render, pos) in (&renderables, &positions).join() {
self.window.mvaddch(pos.y as _, pos.x as _, render.glyph);
}
// Leave the cursor at the lower-left.
self.window.mv(0, 0);
self.window.refresh();
// For now, just get a character to avoid redrawing over and
// over.
self.window.getch();
}
}