Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define a simpler row-major entity encoding for saves #341

Merged
merged 2 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 4 additions & 16 deletions save/src/protos.proto
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,9 @@ message Character {
}

message EntityNode {
// Entities whose origins lie within this node
repeated Archetype archetypes = 1;
}

// A set of entities, all of which have the same components
message Archetype {
// Entity IDs
repeated fixed64 entities = 1;

// Type of components stored in each column
repeated ComponentType component_types = 2;

// Each data represents a dense column of component values of the type identified by the
// component_type at the same index as the column
repeated bytes component_data = 3;
// Entities whose origins lie within this node, each encoded as:
// { entity: u64, component_count: varint, components: [{ type: varint, length: varint, data: [u8] }] }
patowen marked this conversation as resolved.
Show resolved Hide resolved
patowen marked this conversation as resolved.
Show resolved Hide resolved
repeated bytes entities = 1;
}

message VoxelNode {
Expand All @@ -46,6 +34,6 @@ message Chunk {
enum ComponentType {
// 4x4 matrix of f32s
POSITION = 0;
// Varint length tag followed by UTF-8 text
// UTF-8 text
NAME = 1;
}
24 changes: 5 additions & 19 deletions save/src/protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,10 @@ pub struct Character {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct EntityNode {
/// Entities whose origins lie within this node
#[prost(message, repeated, tag = "1")]
pub archetypes: ::prost::alloc::vec::Vec<Archetype>,
}
/// A set of entities, all of which have the same components
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Archetype {
/// Entity IDs
#[prost(fixed64, repeated, tag = "1")]
pub entities: ::prost::alloc::vec::Vec<u64>,
/// Type of components stored in each column
#[prost(enumeration = "ComponentType", repeated, tag = "2")]
pub component_types: ::prost::alloc::vec::Vec<i32>,
/// Each data represents a dense column of component values of the type identified by the
/// component_type at the same index as the column
#[prost(bytes = "vec", repeated, tag = "3")]
pub component_data: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
/// Entities whose origins lie within this node, each encoded as:
/// { entity: u64, component_count: varint, components: \[{ type: varint, length: varint, data: [u8\] }] }
#[prost(bytes = "vec", repeated, tag = "1")]
pub entities: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
Expand All @@ -56,7 +42,7 @@ pub struct Chunk {
pub enum ComponentType {
/// 4x4 matrix of f32s
Position = 0,
/// Varint length tag followed by UTF-8 text
/// UTF-8 text
Name = 1,
}
impl ComponentType {
Expand Down
2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license = "Apache-2.0 OR Zlib"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
postcard = { version = "1.0.4", default-features = false }
postcard = { version = "1.0.4", default-features = false, features = ["use-std"] }
common = { path = "../common" }
tracing = "0.1.10"
tokio = { version = "1.18.2", features = ["rt-multi-thread", "time", "macros", "sync"] }
Expand Down
7 changes: 7 additions & 0 deletions server/src/postcard_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,10 @@ impl postcard::ser_flavors::Flavor for ExtendVec<'_> {
Ok(())
}
}

#[derive(serde::Serialize, serde::Deserialize)]
pub struct SaveEntity {
/// [`EntityId`] value, represented as an array to avoid wastefully varint encoding random bytes
pub entity: [u8; 8],
patowen marked this conversation as resolved.
Show resolved Hide resolved
pub components: Vec<(u64, Vec<u8>)>,
}
58 changes: 31 additions & 27 deletions server/src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use fxhash::{FxHashMap, FxHashSet};
use hecs::Entity;
use rand::rngs::SmallRng;
use rand::{Rng, SeedableRng};
use tracing::{error_span, info, trace};
use save::ComponentType;
use tracing::{error, error_span, info, trace};

use common::{
character_controller, dodeca,
Expand All @@ -22,7 +23,7 @@ use common::{
EntityId, SimConfig, Step,
};

use crate::postcard_helpers;
use crate::postcard_helpers::{self, SaveEntity};

pub struct Sim {
cfg: Arc<SimConfig>,
Expand Down Expand Up @@ -96,35 +97,38 @@ impl Sim {
}

fn snapshot_node(&self, node: NodeId) -> save::EntityNode {
let mut ids = Vec::new();
let mut character_transforms = Vec::new();
let mut character_names = Vec::new();
let entities = self.graph_entities.get(node);

for &entity in entities {
// TODO: Handle entities other than characters
let mut q = self
.world
.query_one::<(&EntityId, &Position, &Character)>(entity)
.unwrap();
let Some((id, pos, ch)) = q.get() else {
let mut entities = Vec::new();
for &entity in self.graph_entities.get(node) {
let Ok(entity) = self.world.entity(entity) else {
error!("stale graph entity {:?}", entity);
continue;
};
let Some(id) = entity.get::<&EntityId>() else {
continue;
};
ids.push(id.to_bits());
postcard_helpers::serialize(pos.local.as_ref(), &mut character_transforms).unwrap();
postcard_helpers::serialize(&ch.name, &mut character_names).unwrap();
let mut components = Vec::new();
if let Some(pos) = entity.get::<&Position>() {
components.push((
ComponentType::Position as u64,
postcard::to_stdvec(pos.local.as_ref()).unwrap(),
));
}
if let Some(ch) = entity.get::<&Character>() {
components.push((ComponentType::Name as u64, ch.name.as_bytes().into()));
}
let mut repr = Vec::new();
postcard_helpers::serialize(
&SaveEntity {
entity: id.to_bits().to_le_bytes(),
components,
},
&mut repr,
)
.unwrap();
entities.push(repr);
}

save::EntityNode {
archetypes: vec![save::Archetype {
entities: ids,
component_types: vec![
save::ComponentType::Position.into(),
save::ComponentType::Name.into(),
],
component_data: vec![character_transforms, character_names],
}],
}
save::EntityNode { entities }
}

pub fn spawn_character(&mut self, hello: ClientHello) -> (EntityId, Entity) {
Expand Down
Loading