diff --git a/blockworld-client/Cargo.toml b/blockworld-client/Cargo.toml index c0d75b4..4b84c3a 100644 --- a/blockworld-client/Cargo.toml +++ b/blockworld-client/Cargo.toml @@ -24,13 +24,14 @@ serde = { version = "1.0.202", features = ["derive", "serde_derive"] } serde_json = "1.0.117" thiserror = "1.0.61" tokio = "1.37.0" -wgpu = "0.20.0" +wgpu = "0.23.0" winit = "0.30.0" slab = "0.4.9" once_cell = "1.19.0" bimap = "0.6.3" enumflags2 = "0.7.10" bevy_ecs = "0.14.1" +egui-wgpu = "0.30.0" [[bin]] name = "blockworld-client" diff --git a/blockworld-client/block/block.rs b/blockworld-client/block/block.rs index a973411..20fb9e3 100644 --- a/blockworld-client/block/block.rs +++ b/blockworld-client/block/block.rs @@ -1,31 +1,22 @@ -use blockworld_utils::ResourceLocation; +use blockworld_utils::{HasResourceLocation, ResourceLocation}; pub type NumberID = u32; -pub trait Block: Send + Sync + 'static { - fn hardness(&self) -> f32; - fn material(&self) -> Material; +pub struct Block { + pub id: ResourceLocation, } -macro_rules! def_basic_block { - ($name:ident, $hardness:literal, $material:expr) => { - #[derive(Eq, PartialEq, Clone, Copy)] - pub struct $name; - impl Block for $name { - fn hardness(&self) -> f32 { - $hardness - } - fn material(&self) -> Material { - $material - } - } - }; +impl HasResourceLocation for Block { + fn get_id(&self) -> ResourceLocation { + self.id.clone() + } } -def_basic_block!(Air, 1.5, Material::Air); -def_basic_block!(Stone, 1.5, Material::Solid); -def_basic_block!(Grass, 0.6, Material::Solid); -def_basic_block!(Dirt, 0.5, Material::Solid); +impl Block { + pub fn new(id: ResourceLocation) -> Self { + Self { id } + } +} #[derive(Debug, Default, Clone, Copy)] pub enum Material { diff --git a/blockworld-client/block/mod.rs b/blockworld-client/block/mod.rs index 8325b5b..2a1857c 100644 --- a/blockworld-client/block/mod.rs +++ b/blockworld-client/block/mod.rs @@ -3,16 +3,12 @@ pub use block::*; use blockworld_utils::Registry; use once_cell::sync::Lazy; -pub static BLOCK_REGISTRY: Lazy> = Lazy::new(|| { +pub static BLOCK_REGISTRY: Lazy> = Lazy::new(|| { let mut r = Registry::new(); + let a0 = Block::new("minecraft:air".into()); + r.register(a0); + let a1 = Block::new("minecraft:stone".into()); + r.register(a1); - let mut number_id = 0; - r.register("air".into(), &Air as &dyn Block); - - number_id += 1; - r.register("stone".into(), &Stone); - - number_id += 1; - r.register("grass".into(), &Grass); r }); diff --git a/blockworld-client/renderer/atlas_image.rs b/blockworld-client/renderer/atlas_image.rs index eb0db24..d4ed84f 100644 --- a/blockworld-client/renderer/atlas_image.rs +++ b/blockworld-client/renderer/atlas_image.rs @@ -72,7 +72,10 @@ impl Atlas { atlas.copy_from(&img, x * tile_size, y * tile_size).unwrap(); let item_name = path.file_stem().unwrap(); - let r = ResourceLocation::new(item_name.to_str().unwrap()); + + let r = ResourceLocation::new( + format!("minecraft:{}", item_name.to_str().unwrap()).as_str(), + ); name_to_xy_map.insert(r, uvec2(x, y)); diff --git a/blockworld-client/renderer/bytes_provider.rs b/blockworld-client/renderer/bytes_provider.rs index eac700f..a53c004 100644 --- a/blockworld-client/renderer/bytes_provider.rs +++ b/blockworld-client/renderer/bytes_provider.rs @@ -1,7 +1,7 @@ +use anyhow::*; use std::path::{Path, PathBuf}; use blockworld_utils::ResourceLocation; -use thiserror::Error; /// A abstraction over the way resources are loaded. /// This trait is implemented by different resource providers, @@ -14,14 +14,14 @@ pub trait BytesProvider: Send + Sync { /// /// `minecraft:textures/block/stone.png` /// `assets/minecraft/textures/block/stone.png` - fn get_bytes(&self, id: &ResourceLocation) -> Result, ResourceError>; + fn get_bytes(&self, id: &ResourceLocation) -> Result>; } /// A resource provider that provides resources from a static value (embedded in the binary). pub struct StaticBytesProvider; impl BytesProvider for StaticBytesProvider { - fn get_bytes(&self, id: &ResourceLocation) -> Result, ResourceError> { + fn get_bytes(&self, id: &ResourceLocation) -> Result> { if id == &"minecraft:assets/shaders/wireframe_shader.wgsl".into() { let r = include_bytes!("shaders/wireframe_shader.wgsl").to_vec(); return Ok(r); @@ -30,7 +30,7 @@ impl BytesProvider for StaticBytesProvider { let r = include_bytes!("shaders/default_shader.wgsl").to_vec(); return Ok(r); } - Err(ResourceError::NotFound(id.clone())) + bail!("Resource not found: {:?}", id); } } @@ -47,7 +47,7 @@ impl FilesystemBytesProvider { } impl BytesProvider for FilesystemBytesProvider { - fn get_bytes(&self, identifier: &ResourceLocation) -> Result, ResourceError> { + fn get_bytes(&self, identifier: &ResourceLocation) -> anyhow::Result> { let path = self .root_dir .join(Path::new("assets/").join(identifier.get_namespace())) @@ -55,28 +55,11 @@ impl BytesProvider for FilesystemBytesProvider { dbg!(&path); if !path.exists() { - return Err(ResourceError::NotFound(identifier.clone())); + anyhow::bail!("File not found: {:?}", path); } - let buf = std::fs::read(path).map_err(|e| ResourceError::Io(e))?; + let buf = std::fs::read(path)?; Ok(buf) } } - -#[derive(Error, Debug)] -pub enum ResourceError { - #[error("Resource not found: {0}")] - NotFound(ResourceLocation), - #[error("IO error: {0}")] - Io(std::io::Error), -} - -#[test] -fn filesystem_resource_provider_test() { - let p = FilesystemBytesProvider::new("."); - let bytes = p - .get_bytes(&ResourceLocation::new("minecraft:texts/splashes.txt")) - .unwrap(); - let s = String::from_utf8(bytes).unwrap(); -} diff --git a/blockworld-client/renderer/wgpu/render_state.rs b/blockworld-client/renderer/wgpu/render_state.rs index 9a867f9..9273636 100644 --- a/blockworld-client/renderer/wgpu/render_state.rs +++ b/blockworld-client/renderer/wgpu/render_state.rs @@ -28,6 +28,8 @@ pub struct RenderState { pub global_timer: Instant, pub world_renderer: WorldRenderer, + + pub egui_renderer: egui_wgpu::Renderer, } impl RenderState { @@ -44,6 +46,8 @@ impl RenderState { let world_renderer = WorldRenderer::new(&device, &config, &queue, size); + let egui_renderer = egui_wgpu::Renderer::new(&device, wgpu::TextureFormat::Rgba8UnormSrgb, None, 4, true); + Self { window: window_arc, surface, @@ -55,6 +59,8 @@ impl RenderState { world_renderer, dt_timer: Instant::now(), global_timer: Instant::now(), + + egui_renderer: } } diff --git a/blockworld-client/world/block_access.rs b/blockworld-client/world/block_access.rs deleted file mode 100644 index b74e0d0..0000000 --- a/blockworld-client/world/block_access.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::block::*; - -/// `IBlockAccess` in minecraft -trait BlockAccess { - fn get_block(&self) -> &'static dyn Block; - // fn get_tile_entity(&self) -> TileEntity; - - /// Returns true if the block at the specified coordinates is empty - fn is_air_block(&self) -> bool; -} diff --git a/blockworld-client/world/chunk.rs b/blockworld-client/world/chunk.rs index 08b47e9..daa42f0 100644 --- a/blockworld-client/world/chunk.rs +++ b/blockworld-client/world/chunk.rs @@ -1,5 +1,9 @@ -use std::{borrow::Cow, ops::Div}; +use std::{ + borrow::{Borrow, Cow}, + ops::Div, +}; +use bevy_ecs::system::Res; use blockworld_utils::ResourceLocation; use enumflags2::{BitFlag, BitFlags}; use glam::*; @@ -16,18 +20,21 @@ pub const CHUNK_BLOCK_NUM: usize = CHUNK_SIZE * CHUNK_SIZE * CHUNK_HEIGHT; // ! Should be optimized later by using 4 bit instead of u8 type LightLevel = u8; -// ExtendedBlockStorage.java pub struct SubChunk { - /// A total count of the number of non-air blocks in this block storage's Chunk. - block_ref_count: u32, - block_array: [&'static str; SUBCHUNK_SIZE * SUBCHUNK_SIZE * SUBCHUNK_SIZE], + // block_palette: Vec, + // in yzx order + // can be empty + // blocks: Option>, + + // temp, low performance + blocks: Box<[u32; 4096]>, } impl SubChunk { pub fn new() -> Self { Self { - block_ref_count: 0, - block_array: core::array::from_fn(|_| "minecraft:air"), + // block_palette: Vec::new(), + blocks: Box::new([0; 4096]), } } @@ -37,27 +44,35 @@ impl SubChunk { /// /// From xyz to Index of the block array. /// - /// Don't pass negative numbers into this function! fn index(x: i32, y: i32, z: i32) -> usize { + // Make sure the index is in the range of 0..15 + assert!( + x >= 0 + && y >= 0 + && z >= 0 + && x <= SUBCHUNK_SIZE as i32 + && y <= SUBCHUNK_SIZE as i32 + && z <= SUBCHUNK_SIZE as i32 + ); + (y * CHUNK_SIZE as i32 * CHUNK_SIZE as i32 + z * CHUNK_SIZE as i32 + x) as usize } - pub fn set_blockid(&mut self, x: i32, y: i32, z: i32, block_id: &'static str) { - self.block_array[Self::index(x, y, z)] = block_id; - if block_id != "minecraft:air" { - self.block_ref_count += 1; - } + pub fn set_blockid(&mut self, x: i32, y: i32, z: i32, block_id: &str) { + let number_id = BLOCK_REGISTRY.name_to_number_id(&block_id.into()); + self.blocks[Self::index(x, y, z)] = number_id; } pub fn remove_block(&mut self, x: i32, y: i32, z: i32) { - if self.block_array[Self::index(x, y, z)] != "minecraft:air" { - self.block_array[Self::index(x, y, z)] = "minecraft:air"; - self.block_ref_count -= 1; - } + self.blocks[Self::index(x, y, z)] = 0; } pub fn get_blockid(&self, x: i32, y: i32, z: i32) -> &'static str { - self.block_array[Self::index(x, y, z)] + if let Some(r) = BLOCK_REGISTRY.number_id_to_name(self.blocks[Self::index(x, y, z)]) { + r + } else { + "minecraft:air" + } } } diff --git a/blockworld-client/world/mod.rs b/blockworld-client/world/mod.rs index 8dc1278..8911b5f 100644 --- a/blockworld-client/world/mod.rs +++ b/blockworld-client/world/mod.rs @@ -4,7 +4,6 @@ use once_cell::sync::Lazy; use crate::renderer::entity::Player; -pub mod block_access; pub mod chunk; pub mod chunk_array;