mirror of
https://github.com/Noratrieb/game-wip-dontplay.git
synced 2026-01-14 19:55:02 +01:00
Make tile ids strongly typed between bg/mid/fg
This commit is contained in:
parent
cdf73d0739
commit
1e665378f8
15 changed files with 448 additions and 178 deletions
56
Cargo.lock
generated
56
Cargo.lock
generated
|
|
@ -158,6 +158,17 @@ version = "0.10.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield-struct"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc92b6a6ac8f8176ab4764440f5129ad73d557c532b7f5c324a71846fd25a9c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
|
@ -296,9 +307,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.7"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
|
||||
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-utils",
|
||||
|
|
@ -400,7 +411,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "egui-inspect"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/crumblingstatue/egui-inspect.git#5cf1f05c0f4f6625eb9a46ee0faebdb27919f9bf"
|
||||
source = "git+https://github.com/crumblingstatue/egui-inspect.git#77b02370966aad6be6eeb94ce88ae9268986fc0d"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"egui-inspect-derive",
|
||||
|
|
@ -409,11 +420,11 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "egui-inspect-derive"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/crumblingstatue/egui-inspect.git#5cf1f05c0f4f6625eb9a46ee0faebdb27919f9bf"
|
||||
source = "git+https://github.com/crumblingstatue/egui-inspect.git#77b02370966aad6be6eeb94ce88ae9268986fc0d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -504,7 +515,7 @@ dependencies = [
|
|||
"flume",
|
||||
"half",
|
||||
"lebe",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.6.2",
|
||||
"rayon-core",
|
||||
"smallvec",
|
||||
"zune-inflate",
|
||||
|
|
@ -519,6 +530,15 @@ dependencies = [
|
|||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fdeflate"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
|
|
@ -526,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.6.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -930,6 +950,7 @@ name = "mantle-diver"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bitfield-struct",
|
||||
"clap",
|
||||
"derivative",
|
||||
"directories",
|
||||
|
|
@ -980,6 +1001,16 @@ dependencies = [
|
|||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nanorand"
|
||||
version = "0.7.0"
|
||||
|
|
@ -1166,14 +1197,15 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
|||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.7"
|
||||
version = "0.17.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638"
|
||||
checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crc32fast",
|
||||
"fdeflate",
|
||||
"flate2",
|
||||
"miniz_oxide",
|
||||
"miniz_oxide 0.7.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1978,9 +2010,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zune-inflate"
|
||||
version = "0.2.51"
|
||||
version = "0.2.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a01728b79fb9b7e28a8c11f715e1cd8dc2cda7416a007d66cac55cebb3a8ac6b"
|
||||
checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8"
|
||||
dependencies = [
|
||||
"simd-adler32",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ directories = "5.0.0"
|
|||
texture_packer = "0.25.0"
|
||||
walkdir = "2.3.3"
|
||||
image = "0.24.6"
|
||||
bitfield-struct = "0.4.1"
|
||||
|
||||
[dependencies.s2dc]
|
||||
#git = "https://github.com/crumblingstatue/s2dc.git"
|
||||
|
|
|
|||
11
design/data.md
Normal file
11
design/data.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Tile
|
||||
|
||||
9 bits bg
|
||||
9 bits mid
|
||||
9 bits fg 32 bits
|
||||
3 bits slope
|
||||
2 bits fg state (0: fg has ore, 1: bg has ore, 2: both have ores)
|
||||
|
||||
5 bits liquid type
|
||||
6 bits paint 16 bits
|
||||
5 bits reserved
|
||||
BIN
res/graphics/tiles/unknown_bg.png
Normal file
BIN
res/graphics/tiles/unknown_bg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
res/graphics/tiles/unknown_fg.png
Normal file
BIN
res/graphics/tiles/unknown_fg.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
res/graphics/tiles/unknown_mid.png
Normal file
BIN
res/graphics/tiles/unknown_mid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
44
src/app.rs
44
src/app.rs
|
|
@ -23,6 +23,7 @@ use crate::{
|
|||
inventory::{ItemId, Slot, TileLayer, UseAction},
|
||||
math::{center_offset, TILE_SIZE},
|
||||
res::Res,
|
||||
tiles::TileId,
|
||||
CliArgs,
|
||||
};
|
||||
|
||||
|
|
@ -158,9 +159,12 @@ impl App {
|
|||
.clamp(-terminal_velocity, terminal_velocity);
|
||||
let mut on_screen_tile_ents = Vec::new();
|
||||
for_each_tile_on_screen(self.game.camera_offset, self.rt.size(), |tp, _sp| {
|
||||
let tid = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid;
|
||||
let tdef = &self.game.tile_db[tid];
|
||||
let Some(bb) = tdef.bb else {
|
||||
let tile = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid;
|
||||
if tile.empty() {
|
||||
return;
|
||||
}
|
||||
let tdef = &self.game.tile_db[tile];
|
||||
let Some(bb) = tdef.layer.bb else {
|
||||
return;
|
||||
};
|
||||
let x = tp.x as i32 * TILE_SIZE as i32;
|
||||
|
|
@ -173,7 +177,7 @@ impl App {
|
|||
);
|
||||
on_screen_tile_ents.push(TileColEn {
|
||||
col: en,
|
||||
platform: tdef.platform,
|
||||
platform: tdef.layer.platform,
|
||||
});
|
||||
});
|
||||
imm_dbg!(on_screen_tile_ents.len());
|
||||
|
|
@ -264,27 +268,25 @@ impl App {
|
|||
let def = &self.game.itemdb.db[active_slot.id as usize];
|
||||
let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen);
|
||||
match &def.use_action {
|
||||
UseAction::PlaceTile { layer, id } => match layer {
|
||||
TileLayer::Bg => {
|
||||
if t.bg == 0 {
|
||||
t.bg = *id
|
||||
}
|
||||
UseAction::PlaceBgTile { id } => {
|
||||
if t.bg.empty() {
|
||||
t.bg = *id
|
||||
}
|
||||
TileLayer::Mid => {
|
||||
if t.mid == 0 {
|
||||
t.mid = *id
|
||||
}
|
||||
}
|
||||
UseAction::PlaceMidTile { id } => {
|
||||
if t.mid.empty() {
|
||||
t.mid = *id
|
||||
}
|
||||
TileLayer::Fg => {
|
||||
if t.fg == 0 {
|
||||
t.fg = *id
|
||||
}
|
||||
}
|
||||
UseAction::PlaceFgTile { id } => {
|
||||
if t.fg.empty() {
|
||||
t.fg = *id
|
||||
}
|
||||
},
|
||||
}
|
||||
UseAction::RemoveTile { layer } => match layer {
|
||||
TileLayer::Bg => t.bg = 0,
|
||||
TileLayer::Mid => t.mid = 0,
|
||||
TileLayer::Fg => t.fg = 0,
|
||||
TileLayer::Bg => t.bg = TileId::EMPTY,
|
||||
TileLayer::Mid => t.mid = TileId::EMPTY,
|
||||
TileLayer::Fg => t.fg = TileId::EMPTY,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
math::{smoothwave, wp_to_tp, WorldPos},
|
||||
res::Res,
|
||||
tiles::TileDb,
|
||||
world::{Tile, TilePos, World},
|
||||
world::{TilePos, World},
|
||||
worldgen::Worldgen,
|
||||
};
|
||||
|
||||
|
|
@ -77,11 +77,11 @@ impl GameState {
|
|||
for_each_tile_on_screen(self.camera_offset, rt.size(), |tp, sp| {
|
||||
let tile = self.world.tile_at_mut(tp, &self.worldgen);
|
||||
s.set_position(sp.to_sf_vec());
|
||||
if tile.bg != Tile::EMPTY {
|
||||
if !tile.bg.empty() {
|
||||
s.set_texture_rect(self.tile_db[tile.bg].tex_rect.to_sf());
|
||||
rt.draw(&s);
|
||||
}
|
||||
if tile.mid != Tile::EMPTY {
|
||||
if !tile.mid.empty() {
|
||||
s.set_texture_rect(self.tile_db[tile.mid].tex_rect.to_sf());
|
||||
if let Some(light) = self.tile_db[tile.mid].light {
|
||||
let pos = ScreenVec {
|
||||
|
|
@ -92,7 +92,7 @@ impl GameState {
|
|||
}
|
||||
rt.draw(&s);
|
||||
}
|
||||
if tile.fg != Tile::EMPTY {
|
||||
if !tile.fg.empty() {
|
||||
s.set_texture_rect(self.tile_db[tile.fg].tex_rect.to_sf());
|
||||
rt.draw(&s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use egui_inspect::derive::Inspect;
|
||||
|
||||
use crate::{math::IntRect, world::TileId};
|
||||
use crate::{
|
||||
math::IntRect,
|
||||
tiles::{BgTileId, FgTileId, MidTileId},
|
||||
};
|
||||
|
||||
/// We won't have more than 65535 different items
|
||||
pub type ItemId = u16;
|
||||
|
|
@ -63,7 +66,9 @@ pub enum TileLayer {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum UseAction {
|
||||
PlaceTile { layer: TileLayer, id: TileId },
|
||||
PlaceBgTile { id: BgTileId },
|
||||
PlaceMidTile { id: MidTileId },
|
||||
PlaceFgTile { id: FgTileId },
|
||||
RemoveTile { layer: TileLayer },
|
||||
}
|
||||
|
||||
|
|
@ -80,9 +85,8 @@ impl Default for ItemDb {
|
|||
name: String::from("Dirt Block"),
|
||||
graphic_name: String::from("tiles/dirt"),
|
||||
tex_rect: IntRect::default(),
|
||||
use_action: UseAction::PlaceTile {
|
||||
layer: TileLayer::Mid,
|
||||
id: 3,
|
||||
use_action: UseAction::PlaceMidTile {
|
||||
id: MidTileId::DIRT,
|
||||
},
|
||||
consumable: true,
|
||||
},
|
||||
|
|
@ -90,9 +94,8 @@ impl Default for ItemDb {
|
|||
name: String::from("Torch"),
|
||||
graphic_name: String::from("tiles/torch"),
|
||||
tex_rect: IntRect::default(),
|
||||
use_action: UseAction::PlaceTile {
|
||||
layer: TileLayer::Mid,
|
||||
id: 4,
|
||||
use_action: UseAction::PlaceMidTile {
|
||||
id: MidTileId::TORCH,
|
||||
},
|
||||
consumable: true,
|
||||
},
|
||||
|
|
@ -100,9 +103,8 @@ impl Default for ItemDb {
|
|||
name: String::from("Platform"),
|
||||
graphic_name: String::from("tiles/platform"),
|
||||
tex_rect: IntRect::default(),
|
||||
use_action: UseAction::PlaceTile {
|
||||
layer: TileLayer::Mid,
|
||||
id: 5,
|
||||
use_action: UseAction::PlaceMidTile {
|
||||
id: MidTileId::PLATFORM,
|
||||
},
|
||||
consumable: true,
|
||||
},
|
||||
|
|
@ -119,9 +121,8 @@ impl Default for ItemDb {
|
|||
name: String::from("Panzerium"),
|
||||
graphic_name: String::from("tiles/panzerium"),
|
||||
tex_rect: IntRect::default(),
|
||||
use_action: UseAction::PlaceTile {
|
||||
layer: TileLayer::Mid,
|
||||
id: 6,
|
||||
use_action: UseAction::PlaceMidTile {
|
||||
id: MidTileId::PANZERIUM,
|
||||
},
|
||||
consumable: true,
|
||||
},
|
||||
|
|
|
|||
289
src/tiles.rs
289
src/tiles.rs
|
|
@ -1,26 +1,186 @@
|
|||
pub mod tiledb_edit_ui;
|
||||
|
||||
use std::ops::Index;
|
||||
use std::{fmt::Debug, marker::PhantomData, ops::Index};
|
||||
|
||||
use egui_inspect::derive::Inspect;
|
||||
use egui_inspect::{derive::Inspect, Inspect};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
graphics::{ScreenSc, ScreenVec},
|
||||
graphics::ScreenVec,
|
||||
math::{IntRect, TILE_SIZE},
|
||||
texture_atlas::RectMap,
|
||||
world::TileId,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Default, Debug, Inspect)]
|
||||
pub struct TileDef {
|
||||
pub bb: Option<TileBb>,
|
||||
#[derive(Inspect, PartialEq, Eq)]
|
||||
pub struct TileId<Layer>(pub u16, PhantomData<Layer>);
|
||||
|
||||
impl<Layer> Copy for TileId<Layer> {}
|
||||
impl<Layer> Clone for TileId<Layer> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0, PhantomData)
|
||||
}
|
||||
}
|
||||
impl<Layer> Debug for TileId<Layer> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("TileId").field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Layer> TileId<Layer> {
|
||||
pub fn empty(&self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
pub const EMPTY: Self = Self(0, PhantomData);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Bg {}
|
||||
#[derive(Debug)]
|
||||
pub enum Mid {}
|
||||
#[derive(Debug)]
|
||||
pub enum Fg {}
|
||||
|
||||
impl Bg {
|
||||
pub fn unknown_def() -> TileDef<Self> {
|
||||
TileDef {
|
||||
light: Some(ScreenVec { x: 0, y: 0 }),
|
||||
graphic_name: String::from("tiles/unknown_bg"),
|
||||
tex_rect: IntRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
},
|
||||
layer: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mid {
|
||||
pub fn unknown_def() -> TileDef<Self> {
|
||||
TileDef {
|
||||
light: Some(ScreenVec { x: 0, y: 0 }),
|
||||
graphic_name: String::from("tiles/unknown_mid"),
|
||||
tex_rect: IntRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
},
|
||||
layer: MidDef {
|
||||
platform: true,
|
||||
bb: Some(TileBb {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 32,
|
||||
h: 32,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Fg {
|
||||
pub fn unknown_def() -> TileDef<Self> {
|
||||
TileDef {
|
||||
light: Some(ScreenVec { x: 0, y: 0 }),
|
||||
graphic_name: String::from("tiles/unknown_fg"),
|
||||
tex_rect: IntRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
},
|
||||
layer: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TileLayer {
|
||||
/// Definitions specific to this layer
|
||||
type SpecificDef;
|
||||
}
|
||||
|
||||
impl TileLayer for Bg {
|
||||
type SpecificDef = ();
|
||||
}
|
||||
|
||||
impl TileLayer for Mid {
|
||||
type SpecificDef = MidDef;
|
||||
}
|
||||
|
||||
impl TileLayer for Fg {
|
||||
type SpecificDef = ();
|
||||
}
|
||||
|
||||
pub type BgTileId = TileId<Bg>;
|
||||
pub type MidTileId = TileId<Mid>;
|
||||
pub type FgTileId = TileId<Fg>;
|
||||
|
||||
impl BgTileId {
|
||||
pub const DIRT: Self = Self(1, PhantomData);
|
||||
pub const STONE: Self = Self(2, PhantomData);
|
||||
}
|
||||
|
||||
impl MidTileId {
|
||||
pub const DIRT: Self = Self(1, PhantomData);
|
||||
pub const STONE: Self = Self(2, PhantomData);
|
||||
pub const TORCH: Self = Self(3, PhantomData);
|
||||
pub const PLATFORM: Self = Self(4, PhantomData);
|
||||
pub const PANZERIUM: Self = Self(5, PhantomData);
|
||||
pub const UNBREAKANIUM: Self = Self(6, PhantomData);
|
||||
}
|
||||
|
||||
impl FgTileId {
|
||||
pub const COAL: Self = Self(1, PhantomData);
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Inspect)]
|
||||
pub struct TileDef<Layer: TileLayer>
|
||||
where
|
||||
Layer::SpecificDef: Debug + Inspect,
|
||||
{
|
||||
/// Whether the tile emits light, and the light source offset
|
||||
pub light: Option<ScreenVec>,
|
||||
/// Platform behavior: Horizontally passable, vertically passable upwards
|
||||
pub platform: bool,
|
||||
pub graphic_name: String,
|
||||
pub tex_rect: IntRect,
|
||||
pub layer: Layer::SpecificDef,
|
||||
}
|
||||
|
||||
#[derive(Debug, Inspect, Default, Serialize, Deserialize)]
|
||||
pub struct MidDef {
|
||||
/// Platform behavior: Horizontally passable, vertically passable upwards
|
||||
pub platform: bool,
|
||||
/// Collision bounding box
|
||||
pub bb: Option<TileBb>,
|
||||
}
|
||||
|
||||
impl<Layer: TileLayer> Debug for TileDef<Layer>
|
||||
where
|
||||
Layer::SpecificDef: Debug + Inspect,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("TileDef")
|
||||
.field("light", &self.light)
|
||||
.field("graphic_name", &self.graphic_name)
|
||||
.field("tex_rect", &self.tex_rect)
|
||||
.field("layer", &self.layer)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<Layer: TileLayer> Default for TileDef<Layer>
|
||||
where
|
||||
Layer::SpecificDef: Default + Debug + Inspect,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
light: Default::default(),
|
||||
graphic_name: Default::default(),
|
||||
tex_rect: Default::default(),
|
||||
layer: Layer::SpecificDef::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DEFAULT_TILE_BB: TileBb = TileBb {
|
||||
|
|
@ -40,49 +200,54 @@ pub struct TileBb {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug, Inspect)]
|
||||
pub struct TileDb {
|
||||
db: Vec<TileDef>,
|
||||
unknown_bg: TileDef<Bg>,
|
||||
unknown_mid: TileDef<Mid>,
|
||||
unknown_fg: TileDef<Fg>,
|
||||
bg: Vec<TileDef<Bg>>,
|
||||
mid: Vec<TileDef<Mid>>,
|
||||
fg: Vec<TileDef<Fg>>,
|
||||
}
|
||||
|
||||
impl Default for TileDb {
|
||||
fn default() -> Self {
|
||||
let unknown = TileDef {
|
||||
bb: None,
|
||||
light: Some(ScreenVec {
|
||||
x: TILE_SIZE as ScreenSc / 2,
|
||||
y: TILE_SIZE as ScreenSc / 2,
|
||||
}),
|
||||
platform: false,
|
||||
graphic_name: String::from("tiles/unknown"),
|
||||
tex_rect: IntRect::default(),
|
||||
};
|
||||
Self {
|
||||
db: vec![EMPTY, unknown],
|
||||
unknown_bg: Bg::unknown_def(),
|
||||
unknown_mid: Mid::unknown_def(),
|
||||
unknown_fg: Fg::unknown_def(),
|
||||
bg: vec![],
|
||||
mid: vec![],
|
||||
fg: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const EMPTY: TileDef = TileDef {
|
||||
bb: None,
|
||||
light: None,
|
||||
// Rendering empty tile is actually special cased, and no rendering is done.
|
||||
// But just in case, put the offset to UNKNOWN
|
||||
tex_rect: IntRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 0,
|
||||
h: 0,
|
||||
},
|
||||
platform: false,
|
||||
graphic_name: String::new(),
|
||||
};
|
||||
impl Index<BgTileId> for TileDb {
|
||||
type Output = TileDef<Bg>;
|
||||
|
||||
impl Index<TileId> for TileDb {
|
||||
type Output = TileDef;
|
||||
fn index(&self, index: BgTileId) -> &Self::Output {
|
||||
self.bg
|
||||
.get(index.0 as usize - 1)
|
||||
.unwrap_or(&self.unknown_bg)
|
||||
}
|
||||
}
|
||||
|
||||
fn index(&self, index: TileId) -> &Self::Output {
|
||||
self.db.get(index as usize).unwrap_or_else(|| {
|
||||
&self.db[1] // Unknown tile def is stored at index 1
|
||||
})
|
||||
impl Index<MidTileId> for TileDb {
|
||||
type Output = TileDef<Mid>;
|
||||
|
||||
fn index(&self, index: MidTileId) -> &Self::Output {
|
||||
self.mid
|
||||
.get(index.0 as usize - 1)
|
||||
.unwrap_or(&self.unknown_mid)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<FgTileId> for TileDb {
|
||||
type Output = TileDef<Fg>;
|
||||
|
||||
fn index(&self, index: FgTileId) -> &Self::Output {
|
||||
self.fg
|
||||
.get(index.0 as usize - 1)
|
||||
.unwrap_or(&self.unknown_fg)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -115,14 +280,38 @@ impl TileDb {
|
|||
}
|
||||
|
||||
pub(crate) fn update_rects(&mut self, rects: &RectMap) {
|
||||
for def in &mut self.db {
|
||||
if !def.graphic_name.is_empty() {
|
||||
if let Some(rect) = rects.get(&def.graphic_name) {
|
||||
def.tex_rect = *rect;
|
||||
} else {
|
||||
log::error!("Missing texture for {}", def.graphic_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
update_rect_def(&mut self.unknown_bg, rects);
|
||||
update_rect_def(&mut self.unknown_mid, rects);
|
||||
update_rect_def(&mut self.unknown_fg, rects);
|
||||
update_rect_db(&mut self.bg, rects);
|
||||
update_rect_db(&mut self.mid, rects);
|
||||
update_rect_db(&mut self.fg, rects);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_rect_db<Layer: TileLayer>(db: &mut Vec<TileDef<Layer>>, rects: &RectMap)
|
||||
where
|
||||
Layer::SpecificDef: Debug + Inspect,
|
||||
{
|
||||
for def in db {
|
||||
update_rect_def(def, rects);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_rect_def<Layer: TileLayer>(
|
||||
def: &mut TileDef<Layer>,
|
||||
rects: &std::collections::HashMap<String, IntRect>,
|
||||
) where
|
||||
Layer::SpecificDef: Debug + Inspect,
|
||||
{
|
||||
if !def.graphic_name.is_empty() {
|
||||
if let Some(rect) = rects.get(def.graphic_name.as_str()) {
|
||||
def.tex_rect = *rect;
|
||||
log::info!("Updated rect for {}: {:?}", def.graphic_name.as_str(), rect);
|
||||
} else {
|
||||
log::error!("Missing texture for {:?}", def.graphic_name.as_str());
|
||||
}
|
||||
} else {
|
||||
log::warn!("Empty graphic name!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,91 @@
|
|||
use std::fmt::Debug;
|
||||
|
||||
use egui_inspect::Inspect;
|
||||
|
||||
use crate::{
|
||||
graphics::{ScreenSc, ScreenVec},
|
||||
math::TILE_SIZE,
|
||||
};
|
||||
|
||||
use super::{TileDb, DEFAULT_TILE_BB};
|
||||
use super::{Bg, Fg, Mid, TileDb, TileDef, TileLayer, DEFAULT_TILE_BB};
|
||||
|
||||
pub fn tiledb_edit_ui(ctx: &egui::Context, tile_db: &mut TileDb) {
|
||||
egui::Window::new("Tiledb editor").show(ctx, |ui| {
|
||||
ui.label(format!("Number of tile defs: {}", tile_db.db.len()));
|
||||
ui.separator();
|
||||
egui::ScrollArea::vertical()
|
||||
.max_height(400.0)
|
||||
.show(ui, |ui| {
|
||||
for (i, def) in tile_db.db.iter_mut().enumerate() {
|
||||
ui.label(i.to_string());
|
||||
match &mut def.light {
|
||||
Some(light) => {
|
||||
ui.label("x");
|
||||
ui.add(egui::DragValue::new(&mut light.x));
|
||||
ui.label("y");
|
||||
ui.add(egui::DragValue::new(&mut light.y));
|
||||
}
|
||||
None => {
|
||||
if ui.button("Insert light emit").clicked() {
|
||||
def.light = Some(ScreenVec {
|
||||
x: TILE_SIZE as ScreenSc / 2,
|
||||
y: TILE_SIZE as ScreenSc / 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
match &mut def.bb {
|
||||
Some(bb) => {
|
||||
ui.label("x");
|
||||
ui.add(egui::DragValue::new(&mut bb.x));
|
||||
ui.label("y");
|
||||
ui.add(egui::DragValue::new(&mut bb.y));
|
||||
ui.label("w");
|
||||
ui.add(egui::DragValue::new(&mut bb.w));
|
||||
ui.label("h");
|
||||
ui.add(egui::DragValue::new(&mut bb.h));
|
||||
}
|
||||
None => {
|
||||
if ui.button("Insert bb").clicked() {
|
||||
def.bb = Some(DEFAULT_TILE_BB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ui.heading("Bg");
|
||||
db_ui(&mut tile_db.bg, ui);
|
||||
ui.heading("Mid");
|
||||
db_ui(&mut tile_db.mid, ui);
|
||||
ui.heading("Fg");
|
||||
db_ui(&mut tile_db.fg, ui);
|
||||
});
|
||||
ui.separator();
|
||||
if ui.button("Add new default").clicked() {
|
||||
tile_db.db.push(super::TileDef::default());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
trait SpecialUi {
|
||||
fn special_ui(&mut self, ui: &mut egui::Ui);
|
||||
}
|
||||
|
||||
impl SpecialUi for TileDef<Mid> {
|
||||
fn special_ui(&mut self, ui: &mut egui::Ui) {
|
||||
match &mut self.layer.bb {
|
||||
Some(bb) => {
|
||||
ui.label("x");
|
||||
ui.add(egui::DragValue::new(&mut bb.x));
|
||||
ui.label("y");
|
||||
ui.add(egui::DragValue::new(&mut bb.y));
|
||||
ui.label("w");
|
||||
ui.add(egui::DragValue::new(&mut bb.w));
|
||||
ui.label("h");
|
||||
ui.add(egui::DragValue::new(&mut bb.h));
|
||||
}
|
||||
None => {
|
||||
if ui.button("Insert bb").clicked() {
|
||||
self.layer.bb = Some(DEFAULT_TILE_BB);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SpecialUi for TileDef<Bg> {
|
||||
fn special_ui(&mut self, _ui: &mut egui::Ui) {}
|
||||
}
|
||||
|
||||
impl SpecialUi for TileDef<Fg> {
|
||||
fn special_ui(&mut self, _ui: &mut egui::Ui) {}
|
||||
}
|
||||
|
||||
fn db_ui<Layer: TileLayer + Debug>(db: &mut Vec<TileDef<Layer>>, ui: &mut egui::Ui)
|
||||
where
|
||||
<Layer as TileLayer>::SpecificDef: Debug + Default + Inspect,
|
||||
TileDef<Layer>: SpecialUi,
|
||||
{
|
||||
for (i, def) in db.iter_mut().enumerate() {
|
||||
ui.label(i.to_string());
|
||||
match &mut def.light {
|
||||
Some(light) => {
|
||||
ui.label("x");
|
||||
ui.add(egui::DragValue::new(&mut light.x));
|
||||
ui.label("y");
|
||||
ui.add(egui::DragValue::new(&mut light.y));
|
||||
}
|
||||
None => {
|
||||
if ui.button("Insert light emit").clicked() {
|
||||
def.light = Some(ScreenVec {
|
||||
x: TILE_SIZE as ScreenSc / 2,
|
||||
y: TILE_SIZE as ScreenSc / 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
def.special_ui(ui);
|
||||
}
|
||||
ui.separator();
|
||||
if ui.button("Add new default").clicked() {
|
||||
db.push(Default::default());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
src/world.rs
27
src/world.rs
|
|
@ -13,7 +13,11 @@ use fnv::FnvHashMap;
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
math::WorldPos, player::Player, world::reg_chunk_existence::ExistenceBitset, worldgen::Worldgen,
|
||||
math::WorldPos,
|
||||
player::Player,
|
||||
tiles::{BgTileId, FgTileId, MidTileId, TileId},
|
||||
world::reg_chunk_existence::ExistenceBitset,
|
||||
worldgen::Worldgen,
|
||||
};
|
||||
|
||||
use self::serialization::save_chunk;
|
||||
|
|
@ -203,9 +207,9 @@ type ChunkTiles = [Tile; CHUNK_N_TILES];
|
|||
|
||||
fn default_chunk_tiles() -> ChunkTiles {
|
||||
[Tile {
|
||||
bg: 0,
|
||||
mid: 0,
|
||||
fg: 0,
|
||||
bg: TileId::EMPTY,
|
||||
mid: TileId::EMPTY,
|
||||
fg: TileId::EMPTY,
|
||||
}; CHUNK_N_TILES]
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +233,7 @@ impl Chunk {
|
|||
// Unbreakable layer at bottom
|
||||
if pos.y > 798 {
|
||||
for b in &mut tiles {
|
||||
b.mid = Tile::UNBREAKANIUM;
|
||||
b.mid = MidTileId::UNBREAKANIUM;
|
||||
}
|
||||
}
|
||||
Self { tiles }
|
||||
|
|
@ -269,21 +273,14 @@ fn chunk_exists(reg_path: &Path, pos: ChunkPos) -> bool {
|
|||
crate::bitmanip::nth_bit_set(bitset.0, idx as usize)
|
||||
}
|
||||
|
||||
pub type TileId = u16;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Inspect)]
|
||||
pub struct Tile {
|
||||
/// Background wall behind entities
|
||||
pub bg: TileId,
|
||||
pub bg: BgTileId,
|
||||
/// The solid wall on the same level as entities
|
||||
pub mid: TileId,
|
||||
pub mid: MidTileId,
|
||||
/// A layer on top of the mid wall. Usually ores or decorative pieces.
|
||||
pub fg: TileId,
|
||||
}
|
||||
|
||||
impl Tile {
|
||||
pub const EMPTY: TileId = 0;
|
||||
pub const UNBREAKANIUM: TileId = 5;
|
||||
pub fg: FgTileId,
|
||||
}
|
||||
|
||||
pub const REGION_CHUNK_EXTENT: u8 = 8;
|
||||
|
|
|
|||
|
|
@ -42,9 +42,9 @@ pub(super) fn save_chunk(pos: &ChunkPos, chk: &Chunk, world_dir: &Path) {
|
|||
let byte_idx = loc_byte_idx(loc_idx);
|
||||
for (i, tile) in chk.tiles.iter().enumerate() {
|
||||
let off = byte_idx + (i * TILE_BYTES);
|
||||
region_tile_data[off..off + 2].copy_from_slice(&tile.bg.to_le_bytes());
|
||||
region_tile_data[off + 2..off + 4].copy_from_slice(&tile.mid.to_le_bytes());
|
||||
region_tile_data[off + 4..off + 6].copy_from_slice(&tile.fg.to_le_bytes());
|
||||
region_tile_data[off..off + 2].copy_from_slice(&tile.bg.0.to_le_bytes());
|
||||
region_tile_data[off + 2..off + 4].copy_from_slice(&tile.mid.0.to_le_bytes());
|
||||
region_tile_data[off + 4..off + 6].copy_from_slice(&tile.fg.0.to_le_bytes());
|
||||
}
|
||||
f.rewind().unwrap();
|
||||
f.write_all(&u64::to_le_bytes(existence_bitset.0)[..])
|
||||
|
|
@ -65,9 +65,9 @@ impl Chunk {
|
|||
let mut tiles = default_chunk_tiles();
|
||||
for (i, t) in tiles.iter_mut().enumerate() {
|
||||
let off = byte_idx + (i * TILE_BYTES);
|
||||
t.bg = u16::from_le_bytes(data[off..off + 2].try_into().unwrap());
|
||||
t.mid = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap());
|
||||
t.fg = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap());
|
||||
t.bg.0 = u16::from_le_bytes(data[off..off + 2].try_into().unwrap());
|
||||
t.mid.0 = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap());
|
||||
t.fg.0 = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap());
|
||||
}
|
||||
Self { tiles }
|
||||
}
|
||||
|
|
@ -83,7 +83,7 @@ fn test_chunk_seri() {
|
|||
tiles: super::default_chunk_tiles(),
|
||||
};
|
||||
for t in &mut chk.tiles {
|
||||
t.bg = 1;
|
||||
t.bg = crate::tiles::BgTileId::DIRT;
|
||||
}
|
||||
save_chunk(&ChunkPos { x: 2, y: 0 }, &chk, "testworld".as_ref());
|
||||
save_chunk(&ChunkPos { x: 3, y: 0 }, &chk, "testworld".as_ref());
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ use worldgen::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::world::{ChunkPos, Tile as Tl, CHUNK_EXTENT};
|
||||
use crate::{
|
||||
tiles::{BgTileId, FgTileId, MidTileId, TileId},
|
||||
world::{ChunkPos, Tile as Tl, CHUNK_EXTENT},
|
||||
};
|
||||
|
||||
pub struct Worldgen {
|
||||
world: World<crate::world::Tile>,
|
||||
|
|
@ -33,35 +36,35 @@ impl Worldgen {
|
|||
// Dirt coal
|
||||
.add(
|
||||
Tile::new(Tl {
|
||||
bg: 9,
|
||||
mid: 3,
|
||||
fg: 6,
|
||||
bg: BgTileId::DIRT,
|
||||
mid: MidTileId::DIRT,
|
||||
fg: FgTileId::COAL,
|
||||
})
|
||||
.when(constraint!(nm.clone(), < -0.8)),
|
||||
)
|
||||
// Dirt
|
||||
.add(
|
||||
Tile::new(Tl {
|
||||
bg: 9,
|
||||
mid: 3,
|
||||
fg: 0,
|
||||
bg: BgTileId::DIRT,
|
||||
mid: MidTileId::DIRT,
|
||||
fg: TileId::EMPTY,
|
||||
})
|
||||
.when(constraint!(nm.clone(), < -0.1)),
|
||||
)
|
||||
// Stone
|
||||
.add(
|
||||
Tile::new(Tl {
|
||||
bg: 7,
|
||||
mid: 2,
|
||||
fg: 0,
|
||||
bg: BgTileId::STONE,
|
||||
mid: MidTileId::STONE,
|
||||
fg: TileId::EMPTY,
|
||||
})
|
||||
.when(constraint!(nm, < 0.45)),
|
||||
)
|
||||
// Dirt wall
|
||||
.add(Tile::new(Tl {
|
||||
bg: 9,
|
||||
mid: 0,
|
||||
fg: 0,
|
||||
bg: BgTileId::DIRT,
|
||||
mid: TileId::EMPTY,
|
||||
fg: TileId::EMPTY,
|
||||
}));
|
||||
Self { world }
|
||||
}
|
||||
|
|
|
|||
BIN
tiles.dat
BIN
tiles.dat
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue