diff options
Diffstat (limited to 'server/src')
-rw-r--r-- | server/src/game.rs | 88 | ||||
-rw-r--r-- | server/src/main.rs | 63 | ||||
-rw-r--r-- | server/src/protocol.rs | 31 |
3 files changed, 182 insertions, 0 deletions
diff --git a/server/src/game.rs b/server/src/game.rs new file mode 100644 index 00000000..0d1e8c3b --- /dev/null +++ b/server/src/game.rs @@ -0,0 +1,88 @@ +use crate::protocol::{Item, PacketC, PacketS, ID}; +use anyhow::{anyhow, Result}; +use glam::UVec2; +use std::collections::{HashMap, VecDeque}; + +struct ItemData {} + +struct TileData { + items: Vec<ID>, + active: bool, +} + +struct Player { + name: String, + hand: Option<ID>, +} + +#[derive(Default)] +pub struct Game { + item_id_counter: ID, + tiles: HashMap<UVec2, TileData>, + items: HashMap<ID, Item>, + players: HashMap<ID, Player>, + packet_out: VecDeque<PacketC>, +} + +impl Game { + pub fn new() -> Self { + Self::default() + } + + pub fn packet_out(&mut self) -> Option<PacketC> { + self.packet_out.pop_front() + } + + pub fn packet_in(&mut self, player: ID, packet: PacketS) -> Result<()> { + match packet { + PacketS::Join { name } => { + self.players.insert( + player, + Player { + hand: None, + name: name.clone(), + }, + ); + self.packet_out + .push_back(PacketC::AddPlayer { id: player, name }); + } + PacketS::Leave => { + let p = self + .players + .remove(&player) + .ok_or(anyhow!("player does not exist"))?; + if let Some(_i) = p.hand { + // TODO what now? + } + self.packet_out + .push_back(PacketC::RemovePlayer { id: player }) + } + PacketS::Position { pos, rot } => { + self.packet_out + .push_back(PacketC::Position { player, pos, rot }); + } + PacketS::Interact { pos } => { + let tile = self + .tiles + .get_mut(&pos) + .ok_or(anyhow!("interacting with empty tile"))?; + let player_data = self + .players + .get_mut(&player) + .ok_or(anyhow!("player does not exist"))?; + + if let Some(item) = player_data.hand.take() { + tile.items.push(item); + self.packet_out.push_back(PacketC::PutItem { item, pos }) + } else { + if let Some(item) = tile.items.pop() { + player_data.hand = Some(item); + self.packet_out + .push_back(PacketC::TakeItem { item, player }) + } + } + } + } + Ok(()) + } +} diff --git a/server/src/main.rs b/server/src/main.rs new file mode 100644 index 00000000..f688cffe --- /dev/null +++ b/server/src/main.rs @@ -0,0 +1,63 @@ +use anyhow::Result; +use game::Game; +use log::info; +use protocol::{PacketC, PacketS}; +use std::{sync::Arc, time::Duration}; +use tokio::{ + io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, + net::TcpListener, + spawn, + sync::{broadcast, RwLock}, + time::sleep, +}; + +pub mod game; +pub mod protocol; + +#[tokio::main] +async fn main() -> Result<()> { + env_logger::init_from_env("LOG"); + let listener = TcpListener::bind("0.0.0.0:27031").await?; + info!("listening on {}", listener.local_addr()?); + + let game = Arc::new(RwLock::new(Game::new())); + let (tx, rx) = broadcast::channel::<PacketC>(1024); + + { + let game = game.clone(); + spawn(async move { + { + let mut g = game.write().await; + while let Some(p) = g.packet_out() { + let _ = tx.send(p); + } + } + sleep(Duration::from_millis(10)).await; + }); + } + + for id in 0.. { + let (sock, addr) = listener.accept().await?; + let (read, mut write) = sock.into_split(); + let game = game.clone(); + let mut rx = rx.resubscribe(); + info!("{addr} connected"); + spawn(async move { + while let Ok(packet) = rx.recv().await { + write + .write_all(serde_json::to_string(&packet).unwrap().as_bytes()) + .await + .unwrap(); + } + }); + spawn(async move { + let mut read = BufReader::new(read).lines(); + while let Ok(Some(line)) = read.next_line().await { + let packet: PacketS = serde_json::from_str(&line).unwrap(); + game.write().await.packet_in(id, packet).unwrap(); + } + }); + } + + Ok(()) +} diff --git a/server/src/protocol.rs b/server/src/protocol.rs new file mode 100644 index 00000000..d463a5d3 --- /dev/null +++ b/server/src/protocol.rs @@ -0,0 +1,31 @@ +use glam::{UVec2, Vec2}; +use serde::{Deserialize, Serialize}; + +pub type ID = u32; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Item {} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Tile {} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PacketS { + Join { name: String }, + Leave, + Position { pos: Vec2, rot: f32 }, + Interact { pos: UVec2 }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PacketC { + AddPlayer { id: ID, name: String }, + RemovePlayer { id: ID }, + Position { player: ID, pos: Vec2, rot: f32 }, + TakeItem { item: ID, player: ID }, + PutItem { item: ID, pos: UVec2 }, + ProduceItem { id: ID, pos: UVec2, kind: Item }, + ConsumeItem { id: ID, pos: UVec2 }, + SetActive { tile: UVec2 }, + UpdateMap { pos: UVec2, tile: Tile }, +} |