Skip to content

Commit

Permalink
Load character entities from the save file
Browse files Browse the repository at this point in the history
  • Loading branch information
patowen authored and Ralith committed Jul 28, 2024
1 parent 6ac2524 commit ad363cc
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 25 deletions.
10 changes: 8 additions & 2 deletions client/src/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use anyhow::{anyhow, Error, Result};
use quinn::rustls;
use tokio::sync::mpsc;

use common::{codec, proto};
use common::{
codec,
proto::{self, connection_error_codes},
};

use crate::Config;

Expand Down Expand Up @@ -126,7 +129,10 @@ async fn handle_unordered(incoming: mpsc::UnboundedSender<Message>, connection:
match codec::recv_whole::<proto::StateDelta>(2usize.pow(16), stream).await {
Err(e) => {
tracing::error!("Error when parsing unordered stream from server: {e}");
connection.close(1u32.into(), b"could not process stream");
connection.close(
connection_error_codes::STREAM_ERROR,
b"could not process stream",
);
}
Ok(msg) => {
let _ = incoming.send(Message::StateDelta(msg));
Expand Down
6 changes: 6 additions & 0 deletions common/src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,12 @@ impl<N: RealField + Copy> MIsometry<N> {
pub fn from_columns_unchecked(columns: &[MVector<N>; 4]) -> Self {
Self(na::Matrix4::from_columns(&(*columns).map(|x| x.0)))
}
/// Creates an `MIsometry` with its elements filled with the components provided by a slice in column-major order.
/// It is the caller's responsibility to ensure that the resulting matrix is a valid isometry.
#[inline]
pub fn from_column_slice_unchecked(data: &[N]) -> Self {
Self(na::Matrix4::from_column_slice(data))
}
/// Minkowski transpose. Inverse for hyperbolic isometries
#[rustfmt::skip]
pub fn mtranspose(self) -> Self {
Expand Down
11 changes: 10 additions & 1 deletion common/src/proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub struct Command {
pub orientation: na::UnitQuaternion<f32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct CharacterInput {
/// Relative to the character's current position, excluding orientation
pub movement: na::Vector3<f32>,
Expand Down Expand Up @@ -114,3 +114,12 @@ pub struct Character {
pub struct Inventory {
pub contents: Vec<EntityId>,
}

pub mod connection_error_codes {
use quinn::VarInt;

pub const CONNECTION_LOST: VarInt = VarInt::from_u32(0);
pub const STREAM_ERROR: VarInt = VarInt::from_u32(1);
pub const BAD_CLIENT_COMMAND: VarInt = VarInt::from_u32(2);
pub const NAME_CONFLICT: VarInt = VarInt::from_u32(3);
}
10 changes: 10 additions & 0 deletions save/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,16 @@ impl Reader {
.map(|n| Ok(n.map_err(GetError::from)?.0.value()))
.collect()
}

/// Temporary function to load all entity-related save data at once.
/// TODO: Replace this implementation with a streaming implementation
/// that does not require loading everything at once
pub fn get_all_entity_node_ids(&self) -> Result<Vec<u128>, GetError> {
self.entity_nodes
.iter()?
.map(|n| Ok(n.map_err(GetError::from)?.0.value()))
.collect()
}
}

fn decompress(
Expand Down
33 changes: 25 additions & 8 deletions server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ use tokio::sync::mpsc;
use tokio_stream::wrappers::{IntervalStream, ReceiverStream};
use tracing::{debug, error, error_span, info, trace};

use common::{codec, proto, SimConfig};
use common::{
codec,
proto::{self, connection_error_codes},
SimConfig,
};
use input_queue::InputQueue;
use save::Save;
use sim::Sim;
Expand Down Expand Up @@ -138,9 +142,10 @@ impl Server {
}
for client_id in overran {
error!("dropping slow client {:?}", client_id.0);
self.clients[client_id]
.conn
.close(1u32.into(), b"client reading too slowly");
self.clients[client_id].conn.close(
connection_error_codes::STREAM_ERROR,
b"client reading too slowly",
);
self.cleanup_client(client_id);
}

Expand All @@ -161,7 +166,14 @@ impl Server {
ClientEvent::Hello(hello) => {
assert!(client.handles.is_none());
let snapshot = Arc::new(self.sim.snapshot());
let (id, entity) = self.sim.spawn_character(hello);
let Some((id, entity)) = self.sim.activate_or_spawn_character(&hello) else {
error!("could not spawn {} due to name conflict", hello.name);
client
.conn
.close(connection_error_codes::NAME_CONFLICT, b"name conflict");
self.cleanup_client(client_id);
return;
};
let (ordered_send, ordered_recv) = mpsc::channel(32);
ordered_send.try_send(snapshot).unwrap();
let (unordered_send, unordered_recv) = mpsc::channel(32);
Expand All @@ -183,7 +195,9 @@ impl Server {
}
ClientEvent::Lost(e) => {
error!("lost: {:#}", e);
client.conn.close(0u32.into(), b"");
client
.conn
.close(connection_error_codes::CONNECTION_LOST, b"");
self.cleanup_client(client_id);
}
ClientEvent::Command(cmd) => {
Expand All @@ -199,7 +213,7 @@ impl Server {

fn cleanup_client(&mut self, client: ClientId) {
if let Some(ref x) = self.clients[client].handles {
self.sim.destroy(x.character);
self.sim.deactivate_character(x.character);
}
self.clients.remove(client);
}
Expand Down Expand Up @@ -249,7 +263,10 @@ async fn drive_recv(
// we want to drop the client. We close the connection, which will cause `drive_recv` to
// return eventually.
tracing::error!("Error when parsing unordered stream from client: {e}");
connection.close(2u32.into(), b"could not process stream");
connection.close(
connection_error_codes::BAD_CLIENT_COMMAND,
b"could not process stream",
);
}
Ok(msg) => {
let _ = send.send((id, ClientEvent::Command(msg))).await;
Expand Down
Loading

0 comments on commit ad363cc

Please sign in to comment.