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

Load character entities from the save file #414

Merged
merged 1 commit into from
Jul 28, 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
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
Loading