summaryrefslogtreecommitdiff
path: root/server/src/state.rs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/state.rs')
-rw-r--r--server/src/state.rs59
1 files changed, 54 insertions, 5 deletions
diff --git a/server/src/state.rs b/server/src/state.rs
index 97261fab..43ca29bd 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -15,18 +15,22 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-use crate::{data::DataIndex, game::Game};
+use crate::{data::DataIndex, game::Game, ConnectionID};
use anyhow::{anyhow, bail, Result};
use clap::{Parser, ValueEnum};
use hurrycurry_protocol::{Message, PacketC, PacketS, PlayerID};
use log::{debug, trace};
-use std::{collections::VecDeque, time::Duration};
+use std::{
+ collections::{HashMap, HashSet, VecDeque},
+ time::Duration,
+};
use tokio::sync::broadcast::Sender;
pub struct State {
index: DataIndex,
packet_out: VecDeque<PacketC>,
tx: Sender<PacketC>,
+ connections: HashMap<ConnectionID, HashSet<PlayerID>>,
pub game: Game,
}
@@ -89,6 +93,7 @@ impl State {
index,
tx,
packet_out,
+ connections: HashMap::new(),
})
}
@@ -110,14 +115,20 @@ impl State {
}
Ok(())
}
- pub async fn packet_in(&mut self, player: PlayerID, packet: PacketS) -> Result<Vec<PacketC>> {
+ pub async fn packet_in(&mut self, conn: ConnectionID, packet: PacketS) -> Result<Vec<PacketC>> {
+ if let Some(p) = get_packet_player(&packet) {
+ if !self.connections.entry(conn).or_default().contains(&p) {
+ bail!("Packet sent to player that is not owned by this connection.");
+ }
+ }
let mut replies = Vec::new();
match &packet {
PacketS::Communicate {
message: Some(Message::Text(text)),
persist: false,
+ player,
} if let Some(command) = text.strip_prefix("/") => {
- match self.handle_command_parse(player, command).await {
+ match self.handle_command_parse(*player, command).await {
Ok(()) => return Ok(vec![]),
Err(e) => {
return Ok(vec![PacketC::ServerMessage {
@@ -126,10 +137,27 @@ impl State {
}
}
}
+ PacketS::Leave { player } => {
+ self.connections.entry(conn).or_default().remove(player);
+ }
+ PacketS::Join { .. } => {
+ if self.connections.entry(conn).or_default().len() > 8 {
+ bail!("Players per connection limit exceeded.")
+ }
+ }
_ => (),
}
self.game
- .packet_in(player, packet, &mut replies, &mut self.packet_out)?;
+ .packet_in(packet, &mut replies, &mut self.packet_out)?;
+
+ for p in &replies {
+ match p {
+ PacketC::Joined { id } => {
+ self.connections.entry(conn).or_default().insert(*id);
+ }
+ _ => (),
+ }
+ }
if self.game.count_chefs() <= 0 && !self.game.lobby {
self.tx
@@ -146,6 +174,15 @@ impl State {
Ok(replies)
}
+ pub async fn disconnect(&mut self, conn: ConnectionID) {
+ if let Some(players) = self.connections.get(&conn) {
+ for player in players.to_owned() {
+ let _ = self.packet_in(conn, PacketS::Leave { player }).await;
+ }
+ }
+ self.connections.remove(&conn);
+ }
+
async fn handle_command_parse(&mut self, player: PlayerID, command: &str) -> Result<()> {
self.handle_command(
player,
@@ -239,3 +276,15 @@ impl State {
Ok(())
}
}
+
+fn get_packet_player(packet: &PacketS) -> Option<PlayerID> {
+ match packet {
+ PacketS::Join { .. } => None,
+ PacketS::Leave { player } => Some(*player),
+ PacketS::Movement { player, .. } => Some(*player),
+ PacketS::Interact { player, .. } => Some(*player),
+ PacketS::Communicate { player, .. } => Some(*player),
+ PacketS::ReplaceHand { player, .. } => Some(*player),
+ PacketS::ReplayTick { .. } => None,
+ }
+}