mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-29 02:08:48 -06:00
hacky shit but it works
This commit is contained in:
parent
ee55ef2d2a
commit
38c0bfa9d1
|
@ -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);
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
pub enum GameState {
|
||||
MainMenu,
|
||||
Connecting,
|
||||
LoadingWorld,
|
||||
InGame
|
||||
}
|
11
src/world.rs
11
src/world.rs
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue