From b146afa72e68f435e3ae3871ebe1e620f40270f9 Mon Sep 17 00:00:00 2001 From: zyl Date: Mon, 9 Sep 2024 16:30:31 -0700 Subject: [PATCH] save player location on save/leave --- Cargo.lock | 1 + Cargo.toml | 4 +-- src/level.rs | 17 ++++++++++-- src/player.rs | 46 +++++++++++++++++++++++-------- src/server.rs | 8 +++++- src/server/network.rs | 63 +++++++++++++++++++++++-------------------- 6 files changed, 94 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e8bd5b..66bcbfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,7 @@ checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" dependencies = [ "cfg-if", "crunchy", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1476225..3cf4243 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ bincode = "2.0.0-rc.3" bitmask-enum = "2" bytes = "1" flate2 = "1" -half = "2" +half = {version = "2", features = ["serde"]} internment = {version = "0.8", features = ["serde"]} nanoid = "0.4" optional_struct = "0.4" @@ -17,6 +17,6 @@ rand = "0.8" safer-bytes = "0.2" serde = {version = "1", features = ["derive"]} serde_json = "1" -strum = { version = "0.26", features = ["derive"] } +strum = {version = "0.26", features = ["derive"]} thiserror = "1" tokio = {version = "1", features = ["full"]} diff --git a/src/level.rs b/src/level.rs index c79d60f..8200244 100644 --- a/src/level.rs +++ b/src/level.rs @@ -1,12 +1,14 @@ use std::{ - collections::BTreeSet, + collections::{BTreeMap, BTreeSet}, io::{Read, Write}, path::Path, }; use serde::{Deserialize, Serialize}; -use crate::{error::GeneralError, packet::server::ServerPacket, util::neighbors}; +use crate::{ + error::GeneralError, packet::server::ServerPacket, player::SavablePlayerData, util::neighbors, +}; use self::block::BLOCK_INFO; @@ -39,6 +41,9 @@ pub struct Level { pub updates: Vec, #[serde(skip)] pub save_now: bool, + + #[serde(default)] + pub player_data: BTreeMap, } impl Level { @@ -53,6 +58,7 @@ impl Level { awaiting_update: Default::default(), updates: Default::default(), save_now: false, + player_data: Default::default(), } } @@ -107,6 +113,13 @@ impl Level { packets } + /// updates player data for the level + pub fn update_player_data(&mut self, player_data: Vec<(String, SavablePlayerData)>) { + for (username, data) in player_data { + self.player_data.insert(username, data); + } + } + /// saves the level pub async fn save

(&self, path: P) -> Result<(), GeneralError> where diff --git a/src/player.rs b/src/player.rs index c127f0d..ab69f78 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,4 +1,7 @@ -use std::net::SocketAddr; +use std::{ + net::SocketAddr, + ops::{Deref, DerefMut}, +}; use half::f16; use serde::{Deserialize, Serialize}; @@ -12,16 +15,8 @@ pub struct Player { pub id: i8, /// the player's username pub username: String, - /// the player's X coordinate - pub x: f16, - /// the player's Y coordinate - pub y: f16, - /// the player's Z coordinate - pub z: f16, - /// the player's yaw - pub yaw: u8, - /// the player's pitch - pub pitch: u8, + /// the player's savable data + pub savable_data: SavablePlayerData, /// the player's permission state pub permissions: PlayerType, @@ -37,6 +32,35 @@ pub struct Player { pub should_be_kicked: Option, } +impl Deref for Player { + type Target = SavablePlayerData; + + fn deref(&self) -> &Self::Target { + &self.savable_data + } +} + +impl DerefMut for Player { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.savable_data + } +} + +/// savable data about the player +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct SavablePlayerData { + /// the player's X coordinate + pub x: f16, + /// the player's Y coordinate + pub y: f16, + /// the player's Z coordinate + pub z: f16, + /// the player's yaw + pub yaw: u8, + /// the player's pitch + pub pitch: u8, +} + /// enum describing types of players #[derive( Debug, diff --git a/src/server.rs b/src/server.rs index 8e733de..d0b1975 100644 --- a/src/server.rs +++ b/src/server.rs @@ -137,7 +137,13 @@ impl Server { // TODO: cancel pending tasks/send out "Server is stopping" messages *here* instead of elsewhere // rn the message isn't guaranteed to actually go out........ - let data = self.data.read().await; + let mut data = self.data.write().await; + let player_data = data + .players + .iter() + .map(|p| (p.username.clone(), p.savable_data.clone())) + .collect(); + data.level.update_player_data(player_data); data.level .save(PathBuf::from(LEVELS_PATH).join(&data.config.level_name)) .await?; diff --git a/src/server/network.rs b/src/server/network.rs index 7094986..55b1ef3 100644 --- a/src/server/network.rs +++ b/src/server/network.rs @@ -122,6 +122,9 @@ pub(super) async fn handle_stream( player.packets_to_send.push(despawn_packet.clone()); player.packets_to_send.push(message_packet.clone()); } + data.level + .player_data + .insert(player.username, player.savable_data); } } @@ -162,8 +165,6 @@ async fn handle_stream_inner( return Err(GeneralError::Custom("Unknown protocol version! Please connect with a classic 0.30-compatible client.".to_string())); } - let zero = f16::from_f32(0.0); - let mut data = data.write().await; match &data.config.protection_mode { @@ -208,15 +209,15 @@ async fn handle_stream_inner( .copied() .unwrap_or_default(); + let savable_data = data.level.player_data.get(&username).cloned(); + let needs_spawn_coords = savable_data.is_none(); + let savable_data = savable_data.unwrap_or_default(); + let mut player = Player { _addr: addr, id: *own_id, // TODO: actually assign user ids username, - x: zero, - y: zero, - z: zero, - yaw: 0, - pitch: 0, + savable_data, permissions: player_type, extensions: ExtBitmask::none(), custom_blocks_support_level: 0, @@ -252,35 +253,39 @@ async fn handle_stream_inner( let username = player.username.clone(); - let (spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch) = - if let Some(spawn) = &data.config.spawn { - (spawn.x, spawn.y, spawn.z, spawn.yaw, spawn.pitch) - } else { - (16.5, (data.level.y_size / 2 + 2) as f32, 16.5, 0, 0) - }; + if needs_spawn_coords { + let (spawn_x, spawn_y, spawn_z, spawn_yaw, spawn_pitch) = + if let Some(spawn) = &data.config.spawn { + (spawn.x, spawn.y, spawn.z, spawn.yaw, spawn.pitch) + } else { + (16.5, (data.level.y_size / 2 + 2) as f32, 16.5, 0, 0) + }; - let (spawn_x, spawn_y, spawn_z) = ( - f16::from_f32(spawn_x), - f16::from_f32(spawn_y), - f16::from_f32(spawn_z), - ); + let (spawn_x, spawn_y, spawn_z) = ( + f16::from_f32(spawn_x), + f16::from_f32(spawn_y), + f16::from_f32(spawn_z), + ); - player.x = spawn_x; - player.y = spawn_y; - player.z = spawn_z; - player.yaw = spawn_yaw; - player.pitch = spawn_pitch; - data.players.push(player); + player.x = spawn_x; + player.y = spawn_y; + player.z = spawn_z; + player.yaw = spawn_yaw; + player.pitch = spawn_pitch; + } let spawn_packet = ServerPacket::SpawnPlayer { player_id: *own_id, player_name: username.clone(), - x: spawn_x, - y: spawn_y, - z: spawn_z, - yaw: spawn_yaw, - pitch: spawn_pitch, + x: player.x, + y: player.y, + z: player.z, + yaw: player.yaw, + pitch: player.pitch, }; + + data.players.push(player); + let message_packet = ServerPacket::Message { player_id: *own_id, message: format!("&e{} has joined the server.", username),