hacky shit but it works

This commit is contained in:
griffi-gh 2023-01-23 02:34:25 +01:00
parent ee55ef2d2a
commit 38c0bfa9d1
7 changed files with 195 additions and 38 deletions

View file

@ -20,11 +20,10 @@ pub(crate) mod player;
pub(crate) mod prefabs;
pub(crate) mod transform;
pub(crate) mod settings;
pub(crate) mod state;
pub(crate) mod camera;
use rendering::{Renderer, RenderTarget, BackgroundColor, clear_background};
use world::{ChunkStorage, ChunkMeshStorage, loading::update_loaded_world_around_player, render::draw_world};
use world::{loading::update_loaded_world_around_player, render::draw_world, init_world};
use player::spawn_player;
use prefabs::load_prefabs;
use settings::GameSettings;
@ -62,12 +61,11 @@ fn main() {
//Add systems and uniques, Init and load things
world.add_unique_non_send_sync(Renderer::init(&event_loop));
world.add_unique_non_send_sync(ChunkMeshStorage::new());
world.add_unique(ChunkStorage::new());
world.add_unique(BackgroundColor(vec3(0.5, 0.5, 1.)));
world.add_unique(DeltaTime(Duration::default()));
world.add_unique(GameSettings::default());
load_prefabs(&world);
init_world(&world);
//Register workloads
world.add_workload(startup);

View file

@ -1,6 +0,0 @@
pub enum GameState {
MainMenu,
Connecting,
LoadingWorld,
InGame
}

View file

@ -1,6 +1,6 @@
use nohash_hasher::BuildNoHashHasher;
use shipyard::Unique;
use glam::{IVec3, ivec3};
use shipyard::{Unique, World};
use glam::IVec3;
use hashbrown::HashMap;
use anyhow::{Result, Context};
@ -14,6 +14,7 @@ pub mod neighbors;
pub mod worldgen;
use chunk::{Chunk, ChunkMesh};
use tasks::ChunkTaskManager;
//TODO separate world struct for render data
// because this is not send-sync
@ -64,3 +65,9 @@ impl ChunkMeshStorage {
self.meshes.get(&key)
}
}
pub fn init_world(world: &World) {
world.add_unique_non_send_sync(ChunkMeshStorage::new());
world.add_unique(ChunkStorage::new());
world.add_unique(ChunkTaskManager::new());
}

View file

@ -8,12 +8,12 @@ pub type BlockData = Box<[[[Block; CHUNK_SIZE]; CHUNK_SIZE]; CHUNK_SIZE]>;
pub struct ChunkData {
pub blocks: BlockData,
pub has_renderable_blocks: bool,
//pub has_renderable_blocks: bool,
}
impl ChunkData {
pub fn update_metadata(&mut self) {
todo!()
}
// pub fn update_metadata(&mut self) {
// todo!()
// }
}
pub struct ChunkMesh {
@ -22,24 +22,33 @@ pub struct ChunkMesh {
pub index_buffer: IndexBuffer<u32>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
pub enum ChunkState {
ToUnload, //desired only
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum CurrentChunkState {
#[default]
Nothing,
Loading, //current only
Loading,
Loaded,
Meshing, //current only
CalculatingMesh,
Rendered,
RecalculatingMesh //current only
RecalculatingMesh,
Unloading,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum DesiredChunkState {
#[default]
Nothing,
Loaded,
Rendered,
ToUnload,
}
pub struct Chunk {
pub position: IVec3,
pub block_data: Option<ChunkData>,
pub mesh_index: Option<usize>,
pub current_state: ChunkState,
pub desired_state: ChunkState,
pub current_state: CurrentChunkState,
pub desired_state: DesiredChunkState,
}
impl Chunk {
pub fn new(position: IVec3) -> Self {

View file

@ -1,12 +1,24 @@
use glam::ivec3;
use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync};
use crate::{player::LocalPlayer, transform::Transform, settings::GameSettings};
use super::{ChunkStorage, chunk::{Chunk, ChunkState, CHUNK_SIZE}, ChunkMeshStorage};
use glam::{IVec3, ivec3};
use glium::{VertexBuffer, IndexBuffer, index::PrimitiveType};
use shipyard::{View, UniqueView, UniqueViewMut, IntoIter, Workload, IntoWorkload, NonSendSync, Nothing};
use crate::{
player::LocalPlayer,
transform::Transform,
settings::GameSettings,
rendering::Renderer
};
use super::{
ChunkStorage, ChunkMeshStorage,
chunk::{Chunk, DesiredChunkState, CHUNK_SIZE, ChunkMesh, CurrentChunkState, ChunkData},
tasks::{ChunkTaskManager, ChunkTaskResponse, ChunkTask},
};
pub fn update_loaded_world_around_player() -> Workload {
(
update_chunks_if_player_moved,
unload_marked_chunks
unload_marked_chunks,
start_required_tasks,
process_completed_tasks,
).into_workload()
}
@ -31,7 +43,7 @@ pub fn update_chunks_if_player_moved(
//Then, mark *ALL* chunks with ToUnload
for (_, chunk) in &mut vm_world.chunks {
chunk.desired_state = ChunkState::ToUnload;
chunk.desired_state = DesiredChunkState::ToUnload;
}
//Then mark chunks that are near to the player
@ -55,8 +67,8 @@ pub fn update_chunks_if_player_moved(
}
};
let desired = match is_border {
true => ChunkState::Loaded,
false => ChunkState::Rendered,
true => DesiredChunkState::Loaded,
false => DesiredChunkState::Rendered,
};
chunk.desired_state = desired;
}
@ -72,7 +84,7 @@ fn unload_marked_chunks(
return
}
vm_world.chunks.retain(|_, chunk| {
if chunk.desired_state == ChunkState::ToUnload {
if chunk.desired_state == DesiredChunkState::ToUnload {
if let Some(mesh_index) = chunk.mesh_index {
vm_meshes.remove(mesh_index).unwrap();
}
@ -83,8 +95,99 @@ fn unload_marked_chunks(
})
}
fn process_tasks(
fn start_required_tasks(
task_manager: UniqueView<ChunkTaskManager>,
mut world: UniqueViewMut<ChunkStorage>,
) {
//HACK: cant iterate over chunks.keys() or chunk directly!
let hashmap_keys: Vec<IVec3> = world.chunks.keys().copied().collect();
for position in hashmap_keys {
let chunk = world.chunks.get(&position).unwrap();
match chunk.desired_state {
DesiredChunkState::Loaded | DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Nothing => {
//start load task
task_manager.spawn_task(ChunkTask::LoadChunk {
seed: 0xdead_cafe,
position
});
//Update chunk state
let chunk = world.chunks.get_mut(&position).unwrap();
chunk.current_state = CurrentChunkState::Loading;
},
DesiredChunkState::Rendered if chunk.current_state == CurrentChunkState::Loaded => {
//get needed data
let Some(neighbors) = world.neighbors_all(position) else {
continue
};
let Some(data) = neighbors.mesh_data() else {
continue
};
//spawn task
task_manager.spawn_task(ChunkTask::GenerateMesh { data, position });
//Update chunk state
let chunk = world.chunks.get_mut(&position).unwrap();
chunk.current_state = CurrentChunkState::CalculatingMesh;
}
_ => ()
}
}
}
fn process_completed_tasks(
task_manager: UniqueView<ChunkTaskManager>,
mut world: UniqueViewMut<ChunkStorage>,
mut meshes: NonSendSync<UniqueViewMut<ChunkMeshStorage>>,
renderer: NonSendSync<UniqueView<Renderer>>
) {
while let Some(res) = task_manager.receive() {
match res {
ChunkTaskResponse::LoadedChunk { position, chunk_data } => {
//check if chunk exists
let Some(chunk) = world.chunks.get_mut(&position) else {
log::warn!("blocks data discarded: chunk doesn't exist");
return
};
//check if chunk still wants it
if matches!(chunk.desired_state, DesiredChunkState::Loaded | DesiredChunkState::Rendered) {
log::warn!("block data discarded: state undesirable");
return
}
//set the block data
chunk.block_data = Some(ChunkData {
blocks: chunk_data
});
//update chunk state
chunk.current_state = CurrentChunkState::Loaded;
},
ChunkTaskResponse::GeneratedMesh { position, vertices, indexes } => {
//check if chunk exists
let Some(chunk) = world.chunks.get_mut(&position) else {
log::warn!("mesh discarded: chunk doesn't exist");
return
};
//check if chunk still wants it
if chunk.desired_state != DesiredChunkState::Rendered {
log::warn!("mesh discarded: state undesirable");
return
}
//apply the mesh
let vertex_buffer = VertexBuffer::new(&renderer.display, &vertices).unwrap();
let index_buffer = IndexBuffer::new(&renderer.display, PrimitiveType::TrianglesList, &indexes).unwrap();
let mesh_index = meshes.insert(ChunkMesh {
is_dirty: false,
vertex_buffer,
index_buffer,
});
chunk.mesh_index = Some(mesh_index);
//update chunk state
chunk.current_state = CurrentChunkState::Rendered;
}
}
}
}

View file

@ -1,2 +1,43 @@
use strum::{EnumIter, IntoEnumIterator};
use glam::{Vec3A, vec3a};
pub mod data;
use data::MeshGenData;
#[repr(usize)]
#[derive(Clone, Copy, Debug, EnumIter)]
pub enum CubeFace {
Top = 0,
Front = 1,
Left = 2,
Right = 3,
Back = 4,
Bottom = 5,
}
const CUBE_FACE_VERTICES: [[Vec3A; 4]; 6] = [
[vec3a(0., 1., 0.), vec3a(0., 1., 1.), vec3a(1., 1., 0.), vec3a(1., 1., 1.)],
[vec3a(0., 0., 0.), vec3a(0., 1., 0.), vec3a(1., 0., 0.), vec3a(1., 1., 0.)],
[vec3a(0., 0., 1.), vec3a(0., 1., 1.), vec3a(0., 0., 0.), vec3a(0., 1., 0.)],
[vec3a(1., 0., 0.), vec3a(1., 1., 0.), vec3a(1., 0., 1.), vec3a(1., 1., 1.)],
[vec3a(1., 0., 1.), vec3a(1., 1., 1.), vec3a(0., 0., 1.), vec3a(0., 1., 1.)],
[vec3a(0., 0., 1.), vec3a(0., 0., 0.), vec3a(1., 0., 1.), vec3a(1., 0., 0.)],
];
const CUBE_FACE_NORMALS: [Vec3A; 6] = [ //this is likely incorrect for a right handed system
vec3a(0., 1., 0.),
vec3a(0., 0., 1.),
vec3a(-1.,0., 0.),
vec3a(1., 0., 0.),
vec3a(0., 0., -1.),
vec3a(0., -1.,0.)
];
const CUBE_FACE_INDICES: [u32; 6] = [0, 1, 2, 2, 1, 3];
const UV_COORDS: [[f32; 2]; 4] = [
[0., 0.],
[0., 1.],
[1., 0.],
[1., 1.],
];
pub fn generate_mesh(data: MeshGenData) {
}

View file

@ -1,5 +1,6 @@
use flume::{Sender, Receiver};
use glam::IVec3;
use shipyard::Unique;
use super::{
chunk::BlockData,
render::ChunkVertex,
@ -29,19 +30,20 @@ pub enum ChunkTaskResponse {
},
}
#[derive(Unique)]
pub struct ChunkTaskManager {
channel: (Sender<ChunkTaskResponse>, Receiver<ChunkTaskResponse>),
}
impl ChunkTaskManager {
pub fn new() -> Self {
Self {
channel: flume::bounded::<ChunkTaskResponse>(0),
channel: flume::unbounded::<ChunkTaskResponse>(), //maybe put a bound or even bound(0)?
}
}
pub fn spawn_task(&self, task: ChunkTask) {
let sender = self.channel.0.clone();
rayon::spawn(move || {
sender.send(match task {
let _ = sender.send(match task {
ChunkTask::GenerateMesh { position, data } => {
todo!()
},
@ -52,4 +54,7 @@ impl ChunkTaskManager {
});
});
}
pub fn receive(&self) -> Option<ChunkTaskResponse> {
self.channel.1.try_recv().ok()
}
}