rezcraft 0.2.0

Minecraft like game written in rust using wgpu, supporting both native and wasm
Documentation
use std::{
    hash::{Hash, Hasher},
    sync::Arc,
};

use block_mesh::ndshape::ConstShape3u32;
use cgmath::{Vector2, Vector3};
use either::Either;
use serde::{Deserialize, Serialize};

use crate::game::world::{Block, BlockBuffer, ChunkData, ChunkMesh, ChunkMeshRaw, LightBuffer, LightPosCache};

pub const CHUNK_SIZE: u32 = 32;
pub const CHUNK_SIZE_VEC: Vector3<i32> = Vector3::new(CHUNK_SIZE as i32, CHUNK_SIZE as i32, CHUNK_SIZE as i32);
pub const CHUNK_SIZE_MESHING: u32 = CHUNK_SIZE + 2;

pub type ChunkShape = ConstShape3u32<CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE>;

#[derive(Serialize, Deserialize)]
pub struct Chunk {
    data: ChunkData,
    #[serde(skip)]
    light_pos_cache_requested_for_state: Option<u64>,
    #[serde(skip)]
    lights_requested_for_state: Option<u64>,
    lights_up_to_date: bool,
    #[serde(skip)]
    mesh: Option<Either<(ChunkMesh, ChunkMesh), (ChunkMeshRaw, ChunkMeshRaw)>>,
    #[serde(skip)]
    mesh_requested_for_state: Option<u64>,
    mesh_up_to_date: bool,
}

impl Chunk {
    pub fn new(blocks: BlockBuffer) -> Self {
        Self {
            data: ChunkData::new(blocks),
            light_pos_cache_requested_for_state: None,
            lights_requested_for_state: None,
            lights_up_to_date: false,
            mesh: None,
            mesh_requested_for_state: None,
            mesh_up_to_date: false,
        }
    }

    // --------------------------------

    pub fn blocks(&self) -> Arc<BlockBuffer> {
        self.data.blocks()
    }

    pub fn set_block(&mut self, in_chunk_pos: &Vector3<i32>, block: Block) -> (bool, bool) {
        self.data.set_block(in_chunk_pos, block)
    }

    // --------------------------------

    pub fn mesh(&mut self, device: &wgpu::Device) -> Option<&(ChunkMesh, ChunkMesh)> {
        if self.mesh.is_some() {
            if self.mesh.as_ref().unwrap().is_right() {
                let mesh_raw = self.mesh.take().unwrap().right().unwrap();
                self.mesh = Some(Either::Left((
                    ChunkMesh::new(mesh_raw.0, device),
                    ChunkMesh::new(mesh_raw.1, device),
                )))
            }
            Some(self.mesh.as_ref().unwrap().as_ref().left().unwrap())
        } else {
            None
        }
    }

    pub fn set_mesh(&mut self, mesh_raw: (ChunkMeshRaw, ChunkMeshRaw)) {
        self.mesh_up_to_date = true;
        self.mesh = Some(Either::Right(mesh_raw))
    }

    pub fn mesh_requested(&self) -> bool {
        if let Some(hash) = self.mesh_requested_for_state {
            hash == self.state_hash()
        } else {
            false
        }
    }

    pub fn set_mesh_requested(&mut self, val: bool) {
        if val {
            self.mesh_requested_for_state = Some(self.state_hash())
        } else {
            self.mesh_requested_for_state = None
        }
    }

    pub fn mesh_up_to_date(&self) -> bool {
        self.mesh_up_to_date
    }

    pub fn set_mesh_outdated(&mut self) {
        self.mesh_up_to_date = false
    }

    // --------------------------------

    pub fn set_light_source_caches(
        &mut self,
        light_source_cache: LightPosCache<0>,
        sunlight_source_cache: LightPosCache<1>,
    ) {
        self.data
            .set_light_source_caches(light_source_cache, sunlight_source_cache)
    }

    pub fn light_pos_cache_requested(&self) -> bool {
        if let Some(hash) = self.light_pos_cache_requested_for_state {
            hash == self.state_hash()
        } else {
            false
        }
    }

    pub fn set_light_pos_cache_requested(&mut self, val: bool) {
        if val {
            self.light_pos_cache_requested_for_state = Some(self.state_hash())
        } else {
            self.light_pos_cache_requested_for_state = None
        }
    }

    // --------------------------------

    pub fn lights(&self) -> Option<Arc<LightBuffer>> {
        self.data.lights()
    }

    pub fn set_lights(&mut self, lights: LightBuffer) {
        self.lights_up_to_date = true;
        self.data.set_lights(lights)
    }

    pub fn lights_requested(&self) -> bool {
        if let Some(hash) = self.lights_requested_for_state {
            hash == self.state_hash()
        } else {
            false
        }
    }

    pub fn set_lights_requested(&mut self, val: bool) {
        if val {
            self.lights_requested_for_state = Some(self.state_hash())
        } else {
            self.lights_requested_for_state = None
        }
    }

    pub fn lights_up_to_date(&self) -> bool {
        self.lights_up_to_date
    }

    pub fn set_lights_outdated(&mut self) {
        self.lights_up_to_date = false
    }

    // --------------------------------

    pub fn update_sunlight_in_collum(&mut self, collum: &Vector2<u32>, highest_block_in_chunk_sees_sky: bool) {
        self.data
            .update_sunlight_in_collum(collum, highest_block_in_chunk_sees_sky)
    }

    pub fn refresh_sunlight_in_collum(&mut self, collum: &Vector2<u32>) {
        self.data.refresh_sunlight_in_collum(collum)
    }

    pub fn do_cache_updates(&mut self, surrounding_blocks: &[Arc<BlockBuffer>; 27]) {
        self.data.do_cache_updates(surrounding_blocks)
    }

    // --------------------------------

    pub fn state_hash(&self) -> u64 {
        let mut hasher = rustc_hash::FxHasher::default();

        self.data.hash(&mut hasher);

        hasher.finish()
    }
}

pub fn coordinate_in_surrounding_buffers(in_chunk_pos: Vector3<i32>) -> Option<(Vector3<i32>, Vector3<i32>)> {
    let chunk_pos = Vector3::<i32>::new(
        if in_chunk_pos.x < 0 {
            -1
        } else if in_chunk_pos.x >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
        if in_chunk_pos.y < 0 {
            -1
        } else if in_chunk_pos.y >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
        if in_chunk_pos.z < 0 {
            -1
        } else if in_chunk_pos.z >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
    );

    {
        if (chunk_pos.x.abs() + chunk_pos.y.abs() + chunk_pos.z.abs()) > 1 {
            None
        } else {
            Some((
                chunk_pos,
                (in_chunk_pos % CHUNK_SIZE as i32 + CHUNK_SIZE_VEC) % CHUNK_SIZE as i32,
            ))
        }
    }
}

pub fn coordinate_in_surrounding_buffers_cube(in_chunk_pos: Vector3<i32>) -> (Vector3<i32>, Vector3<i32>) {
    let chunk_pos = Vector3::<i32>::new(
        if in_chunk_pos.x < 0 {
            -1
        } else if in_chunk_pos.x >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
        if in_chunk_pos.y < 0 {
            -1
        } else if in_chunk_pos.y >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
        if in_chunk_pos.z < 0 {
            -1
        } else if in_chunk_pos.z >= CHUNK_SIZE as i32 {
            1
        } else {
            0
        },
    );

    (
        chunk_pos,
        (in_chunk_pos % CHUNK_SIZE as i32 + CHUNK_SIZE_VEC) % CHUNK_SIZE as i32,
    )
}