Skip to content

Commit

Permalink
Allow the server to send updated chunks to new clients
Browse files Browse the repository at this point in the history
  • Loading branch information
patowen committed Dec 7, 2023
1 parent fe227b1 commit 1531899
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 2 deletions.
10 changes: 9 additions & 1 deletion client/src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use common::{
collision_math::Ray,
graph::{Graph, NodeId},
graph_ray_casting,
node::populate_fresh_nodes,
node::{populate_fresh_nodes, VoxelData},
proto::{
self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component, Position,
},
Expand Down Expand Up @@ -305,6 +305,14 @@ impl Sim {
tracing::error!("Voxel data received from server for ungenerated chunk.")
}
}
for (chunk_id, voxel_data) in msg.modified_chunks {
let Some(voxel_data) = VoxelData::from_serializable(&voxel_data, self.cfg.chunk_size)
else {
tracing::error!("Voxel data received from server is invalid");
continue;
};
self.graph.populate_chunk(chunk_id, voxel_data, true);
}
}

fn spawn(
Expand Down
38 changes: 37 additions & 1 deletion common/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::collision_math::Ray;
use crate::dodeca::Vertex;
use crate::graph::{Graph, NodeId};
use crate::lru_slab::SlotId;
use crate::proto::{BlockUpdate, Position};
use crate::proto::{BlockUpdate, Position, SerializableVoxelData};
use crate::world::Material;
use crate::worldgen::NodeState;
use crate::{math, Chunks};
Expand Down Expand Up @@ -297,6 +297,42 @@ impl VoxelData {
VoxelData::Solid(_) => true,
}
}

pub fn from_serializable(serializable: &SerializableVoxelData, dimension: u8) -> Option<Self> {
if serializable.voxels.len() != usize::from(dimension).pow(3) {
return None;
}

let mut data = vec![Material::Void; (usize::from(dimension) + 2).pow(3)];
let mut input_index = 0;
for x in 0..dimension {
for y in 0..dimension {
for z in 0..dimension {
data[Coords([x, y, z]).to_index(dimension)] = serializable.voxels[input_index];
input_index += 1;
}
}
}
Some(VoxelData::Dense(data.into_boxed_slice()))
}

pub fn to_serializable(&self, dimension: u8) -> SerializableVoxelData {
let VoxelData::Dense(data) = self else {
panic!("Only dense chunks can be serialized.");
};

let mut serializable: Vec<Material> = Vec::with_capacity(usize::from(dimension).pow(3));
for x in 0..dimension {
for y in 0..dimension {
for z in 0..dimension {
serializable.push(data[Coords([x, y, z]).to_index(dimension)]);
}
}
}
SerializableVoxelData {
voxels: serializable,
}
}
}

/// Contains the context needed to know the locations of individual cubes within a chunk in the chunk's coordinate
Expand Down
6 changes: 6 additions & 0 deletions common/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub struct Spawns {
pub despawns: Vec<EntityId>,
pub nodes: Vec<FreshNode>,
pub block_updates: Vec<BlockUpdate>,
pub modified_chunks: Vec<(ChunkId, SerializableVoxelData)>,
}

#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -82,6 +83,11 @@ pub struct BlockUpdate {
pub new_material: Material,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SerializableVoxelData {
pub voxels: Vec<Material>,
}

#[derive(Debug, Serialize, Deserialize)]
pub enum Component {
Character(Character),
Expand Down
1 change: 1 addition & 0 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ impl Server {
|| !spawns.despawns.is_empty()
|| !spawns.nodes.is_empty()
|| !spawns.block_updates.is_empty()
|| !spawns.modified_chunks.is_empty()
{
handles.ordered.try_send(spawns.clone())
} else {
Expand Down
24 changes: 24 additions & 0 deletions server/src/sim.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::sync::Arc;

use common::dodeca::Vertex;
use common::proto::BlockUpdate;
use common::{node::ChunkId, GraphEntities};
use fxhash::{FxHashMap, FxHashSet};
Expand Down Expand Up @@ -35,6 +36,7 @@ pub struct Sim {
despawns: Vec<EntityId>,
graph_entities: GraphEntities,
dirty_nodes: FxHashSet<NodeId>,
modified_chunks: FxHashMap<NodeId, FxHashSet<Vertex>>,
}

impl Sim {
Expand All @@ -49,6 +51,7 @@ impl Sim {
despawns: Vec::new(),
graph_entities: GraphEntities::new(),
dirty_nodes: FxHashSet::default(),
modified_chunks: FxHashMap::default(),
cfg,
};

Expand Down Expand Up @@ -188,10 +191,26 @@ impl Sim {
.map(|(side, parent)| FreshNode { side, parent })
.collect(),
block_updates: Vec::new(),
modified_chunks: Vec::new(),
};
for (entity, &id) in &mut self.world.query::<&EntityId>() {
spawns.spawns.push((id, dump_entity(&self.world, entity)));
}
for chunk_id in self
.modified_chunks
.iter()
.flat_map(|pair| pair.1.iter().map(move |vert| ChunkId::new(*pair.0, *vert)))
{
let voxels =
match self.graph.get(chunk_id.node).as_ref().unwrap().chunks[chunk_id.vertex] {
Chunk::Populated { ref voxels, .. } => voxels,
_ => panic!("ungenerated chunk is marked as modified"),
};

spawns
.modified_chunks
.push((chunk_id, voxels.to_serializable(self.cfg.chunk_size)));
}
spawns
}

Expand Down Expand Up @@ -233,6 +252,10 @@ impl Sim {
if !self.graph.update_block(&block_update) {
tracing::warn!("Block update received from ungenerated chunk");
}
self.modified_chunks
.entry(block_update.chunk_id.node)
.or_default()
.insert(block_update.chunk_id.vertex);
accepted_block_updates.push(block_update);
}

Expand Down Expand Up @@ -262,6 +285,7 @@ impl Sim {
})
.collect(),
block_updates: accepted_block_updates,
modified_chunks: vec![],
};
populate_fresh_nodes(&mut self.graph);

Expand Down

0 comments on commit 1531899

Please sign in to comment.