aboutsummaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'server/src')
-rw-r--r--server/src/game.rs88
-rw-r--r--server/src/main.rs63
-rw-r--r--server/src/protocol.rs31
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 },
+}