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

Replace generic Graph with concrete implemetation and include ChunkLayout #315

Merged
merged 4 commits into from
Oct 30, 2023
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
8 changes: 4 additions & 4 deletions client/src/prediction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::collections::VecDeque;

use common::{
character_controller,
node::DualGraph,
graph::Graph,
proto::{CharacterInput, Position},
SimConfig,
};
Expand Down Expand Up @@ -35,7 +35,7 @@ impl PredictedMotion {

/// Update for input about to be sent to the server, returning the generation it should be
/// tagged with
pub fn push(&mut self, cfg: &SimConfig, graph: &DualGraph, input: &CharacterInput) -> u16 {
pub fn push(&mut self, cfg: &SimConfig, graph: &Graph, input: &CharacterInput) -> u16 {
character_controller::run_character_step(
cfg,
graph,
Expand All @@ -54,7 +54,7 @@ impl PredictedMotion {
pub fn reconcile(
&mut self,
cfg: &SimConfig,
graph: &DualGraph,
graph: &Graph,
generation: u16,
position: Position,
velocity: na::Vector3<f32>,
Expand Down Expand Up @@ -113,7 +113,7 @@ mod tests {
#[test]
fn wraparound() {
let mock_cfg = SimConfig::from_raw(&common::SimConfigRaw::default());
let mut mock_graph = DualGraph::new();
let mut mock_graph = Graph::new(1);
common::node::populate_fresh_nodes(&mut mock_graph);
let mock_character_input = CharacterInput {
movement: na::Vector3::x(),
Expand Down
8 changes: 4 additions & 4 deletions client/src/sim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ use crate::{
};
use common::{
character_controller,
graph::NodeId,
node::{populate_fresh_nodes, DualGraph},
graph::{Graph, NodeId},
node::populate_fresh_nodes,
proto::{self, Character, CharacterInput, CharacterState, Command, Component, Position},
sanitize_motion_input, EntityId, GraphEntities, SimConfig, Step,
};

/// Game state
pub struct Sim {
// World state
pub graph: DualGraph,
pub graph: Graph,
pub graph_entities: GraphEntities,
entity_ids: FxHashMap<EntityId, Entity>,
pub world: hecs::World,
Expand Down Expand Up @@ -53,7 +53,7 @@ pub struct Sim {

impl Sim {
pub fn new(cfg: SimConfig, local_character_id: EntityId) -> Self {
let mut graph = DualGraph::new();
let mut graph = Graph::new(cfg.chunk_size as usize);
populate_fresh_nodes(&mut graph);
Self {
graph,
Expand Down
8 changes: 4 additions & 4 deletions common/benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use common::{
dodeca::{Side, Vertex},
graph::{Graph, NodeId},
node::Chunk,
node::{populate_fresh_nodes, ChunkId, DualGraph},
node::{populate_fresh_nodes, ChunkId},
proto::Position,
traversal::ensure_nearby,
worldgen::ChunkParams,
Expand All @@ -13,7 +13,7 @@ use common::{
fn build_graph(c: &mut Criterion) {
c.bench_function("build_graph 1000", |b| {
b.iter(|| {
let mut graph = Graph::<()>::new();
let mut graph = Graph::new(12);
let mut n = NodeId::ROOT;
for _ in 0..500 {
n = graph.ensure_neighbor(n, Side::A);
Expand All @@ -25,7 +25,7 @@ fn build_graph(c: &mut Criterion) {

c.bench_function("nodegen 1000", |b| {
b.iter(|| {
let mut graph = DualGraph::new();
let mut graph = Graph::new(12);
let mut n = NodeId::ROOT;
for _ in 0..500 {
n = graph.ensure_neighbor(n, Side::A);
Expand All @@ -38,7 +38,7 @@ fn build_graph(c: &mut Criterion) {

c.bench_function("worldgen", |b| {
b.iter(|| {
let mut graph = DualGraph::new();
let mut graph = Graph::new(12);
ensure_nearby(&mut graph, &Position::origin(), 3.0);
let fresh = graph.fresh().to_vec();
populate_fresh_nodes(&mut graph);
Expand Down
10 changes: 2 additions & 8 deletions common/src/character_controller/collision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

use tracing::error;

use crate::{
graph_collision, math,
node::{ChunkLayout, DualGraph},
proto::Position,
};
use crate::{graph::Graph, graph_collision, math, proto::Position};

/// Checks for collisions when a character moves with a character-relative displacement vector of `relative_displacement`.
pub fn check_collision(
Expand All @@ -32,7 +28,6 @@ pub fn check_collision(
let cast_hit = graph_collision::sphere_cast(
collision_context.radius,
collision_context.graph,
&collision_context.chunk_layout,
position,
&ray,
tanh_distance,
Expand Down Expand Up @@ -71,8 +66,7 @@ pub fn check_collision(

/// Contains information about the character and the world that is only relevant for collision checking
pub struct CollisionContext<'a> {
pub graph: &'a DualGraph,
pub chunk_layout: ChunkLayout,
pub graph: &'a Graph,
pub radius: f32,
}

Expand Down
5 changes: 2 additions & 3 deletions common/src/character_controller/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::{
collision::{check_collision, Collision, CollisionContext},
vector_bounds::{BoundedVectors, VectorBound},
},
graph::Graph,
math,
node::{ChunkLayout, DualGraph},
proto::{CharacterInput, Position},
sanitize_motion_input,
sim_config::CharacterConfig,
Expand All @@ -21,7 +21,7 @@ use crate::{
/// Runs a single step of character movement
pub fn run_character_step(
sim_config: &SimConfig,
graph: &DualGraph,
graph: &Graph,
position: &mut Position,
velocity: &mut na::Vector3<f32>,
on_ground: &mut bool,
Expand All @@ -32,7 +32,6 @@ pub fn run_character_step(
cfg: &sim_config.character,
collision_context: CollisionContext {
graph,
chunk_layout: ChunkLayout::new(sim_config.chunk_size as usize),
radius: sim_config.character.character_radius,
},
up: graph.get_relative_up(position).unwrap(),
Expand Down
6 changes: 3 additions & 3 deletions common/src/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Cursor {
}

/// Get the neighbor towards `dir`
pub fn step<N>(self, graph: &Graph<N>, dir: Dir) -> Option<Self> {
pub fn step(self, graph: &Graph, dir: Dir) -> Option<Self> {
// For a cube identified by three dodecahedral faces sharing a vertex, we identify its
// cubical neighbors by taking each vertex incident to exactly two of the faces and the face
// of the three it's not incident to, and selecting the cube represented by the new vertex
Expand Down Expand Up @@ -50,7 +50,7 @@ impl Cursor {
}

/// Node and dodecahedral vertex that contains the representation for this cube in the graph
pub fn canonicalize<N>(self, graph: &Graph<N>) -> Option<ChunkId> {
pub fn canonicalize(self, graph: &Graph) -> Option<ChunkId> {
graph.canonicalize(ChunkId::new(
self.node,
Vertex::from_sides(self.a, self.b, self.c).unwrap(),
Expand Down Expand Up @@ -147,7 +147,7 @@ mod tests {

#[test]
fn cursor_identities() {
let mut graph = Graph::<()>::new();
let mut graph = Graph::new(1);
ensure_nearby(&mut graph, &Position::origin(), 3.0);
let start = Cursor::from_vertex(NodeId::ROOT, Vertex::A);
let wiggle = |dir| {
Expand Down
68 changes: 34 additions & 34 deletions common/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,34 @@ use serde::{Deserialize, Serialize};
use crate::{
dodeca::{Side, SIDE_COUNT},
math,
node::ChunkId,
node::{ChunkId, ChunkLayout, Node},
};

/// Graph of the right dodecahedral tiling of H^3
#[derive(Debug, Clone)]
pub struct Graph<N> {
nodes: FxHashMap<NodeId, Node<N>>,
pub struct Graph {
nodes: FxHashMap<NodeId, NodeContainer>,
/// This field stores implicitly added nodes to ensure that they're initialized in the correct
/// order
fresh: Vec<NodeId>,
layout: ChunkLayout,
}

impl<N> Graph<N> {
pub fn new() -> Self {
impl Graph {
pub fn new(dimension: usize) -> Self {
let mut nodes = FxHashMap::default();
nodes.insert(NodeId::ROOT, Node::new(None, 0));
nodes.insert(NodeId::ROOT, NodeContainer::new(None, 0));
Self {
nodes,
fresh: vec![NodeId::ROOT],
layout: ChunkLayout::new(dimension),
}
}

#[inline]
pub fn layout(&self) -> &ChunkLayout {
&self.layout
}

#[inline]
pub fn len(&self) -> u32 {
self.nodes.len() as u32
Expand Down Expand Up @@ -93,12 +99,12 @@ impl<N> Graph<N> {
}

#[inline]
pub fn get(&self, node: NodeId) -> &Option<N> {
pub fn get(&self, node: NodeId) -> &Option<Node> {
&self.nodes[&node].value
}

#[inline]
pub fn get_mut(&mut self, node: NodeId) -> &mut Option<N> {
pub fn get_mut(&mut self, node: NodeId) -> &mut Option<Node> {
&mut self.nodes.get_mut(&node).unwrap().value
}

Expand Down Expand Up @@ -146,7 +152,7 @@ impl<N> Graph<N> {
}

/// Iterate over every node and its parent except the root
pub fn tree(&self) -> TreeIter<'_, N> {
pub fn tree(&self) -> TreeIter<'_> {
TreeIter::new(self)
}

Expand Down Expand Up @@ -205,7 +211,8 @@ impl<N> Graph<N> {
let id = NodeId(u128::from_le_bytes(hash));

let length = self.nodes[&parent].length + 1;
self.nodes.insert(id, Node::new(Some(side), length));
self.nodes
.insert(id, NodeContainer::new(Some(side), length));
self.link_neighbors(id, parent, side);
for (side, neighbor) in shorter_neighbors {
self.link_neighbors(id, neighbor, side);
Expand Down Expand Up @@ -253,29 +260,22 @@ impl<N> Graph<N> {
}
}

impl<N> Default for Graph<N> {
fn default() -> Self {
Self::new()
}
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct NodeId(u128);

impl NodeId {
pub const ROOT: Self = Self(0);
}

#[derive(Debug, Clone)]
struct Node<N> {
value: Option<N>,
struct NodeContainer {
value: Option<Node>,
parent_side: Option<Side>,
/// Distance to origin via parents
length: u32,
neighbors: [Option<NodeId>; SIDE_COUNT],
}

impl<N> Node<N> {
impl NodeContainer {
fn new(parent_side: Option<Side>, length: u32) -> Self {
Self {
value: None,
Expand All @@ -291,14 +291,14 @@ impl<N> Node<N> {
}

// Iterates through the graph with breadth-first search
pub struct TreeIter<'a, N> {
pub struct TreeIter<'a> {
queue: VecDeque<NodeId>,
visited: FxHashSet<NodeId>,
nodes: &'a FxHashMap<NodeId, Node<N>>,
nodes: &'a FxHashMap<NodeId, NodeContainer>,
}

impl<'a, N> TreeIter<'a, N> {
fn new(graph: &'a Graph<N>) -> Self {
impl<'a> TreeIter<'a> {
fn new(graph: &'a Graph) -> Self {
let mut result = TreeIter {
queue: VecDeque::from([NodeId::ROOT]),
visited: FxHashSet::from_iter([NodeId::ROOT]),
Expand All @@ -312,7 +312,7 @@ impl<'a, N> TreeIter<'a, N> {
}

// Returns the next Node in the traversal. The iterator returns its parent and parent side.
fn next_node(&mut self) -> Option<&Node<N>> {
fn next_node(&mut self) -> Option<&NodeContainer> {
let node_id = self.queue.pop_front()?;
let node = &self.nodes[&node_id];
for side in Side::iter() {
Expand All @@ -327,7 +327,7 @@ impl<'a, N> TreeIter<'a, N> {
}
}

impl<N> Iterator for TreeIter<'_, N> {
impl Iterator for TreeIter<'_> {
type Item = (Side, NodeId);

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -346,7 +346,7 @@ mod tests {

#[test]
fn parent_child_relationships() {
let mut graph = Graph::<()>::default();
let mut graph = Graph::new(1);
assert_eq!(graph.len(), 1);
let a = graph.ensure_neighbor(NodeId::ROOT, Side::A);
assert_eq!(graph.len(), 2);
Expand All @@ -366,7 +366,7 @@ mod tests {

#[test]
fn children_have_common_neighbor() {
let mut graph = Graph::<()>::default();
let mut graph = Graph::new(1);
let a = graph.ensure_neighbor(NodeId::ROOT, Side::A);
let b = graph.ensure_neighbor(NodeId::ROOT, Side::B);
let a_neighbors = Side::iter()
Expand All @@ -393,7 +393,7 @@ mod tests {

#[test]
fn normalize_transform() {
let mut graph = Graph::<()>::default();
let mut graph = Graph::new(1);
let a = graph.ensure_neighbor(NodeId::ROOT, Side::A);
{
let (node, xf) =
Expand All @@ -410,9 +410,9 @@ mod tests {

#[test]
fn rebuild_from_tree() {
let mut a = Graph::<()>::default();
let mut a = Graph::new(1);
ensure_nearby(&mut a, &Position::origin(), 3.0);
let mut b = Graph::<()>::default();
let mut b = Graph::new(1);
for (side, parent) in a.tree() {
b.insert_child(parent, side);
}
Expand All @@ -426,14 +426,14 @@ mod tests {
#[test]
fn hash_consistency() {
let h1 = {
let mut g = Graph::<()>::new();
let mut g = Graph::new(1);
let n1 = g.ensure_neighbor(NodeId::ROOT, Side::A);
let n2 = g.ensure_neighbor(n1, Side::B);
let n3 = g.ensure_neighbor(n2, Side::C);
g.ensure_neighbor(n3, Side::D)
};
let h2 = {
let mut g = Graph::<()>::new();
let mut g = Graph::new(1);
let n1 = g.ensure_neighbor(NodeId::ROOT, Side::C);
let n2 = g.ensure_neighbor(n1, Side::A);
let n3 = g.ensure_neighbor(n2, Side::B);
Expand Down
Loading
Loading