diff --git a/games/rstnode/rst-client/src/assets.rs b/games/rstnode/rst-client/src/assets.rs index 76556213fc7..80f58ee585c 100644 --- a/games/rstnode/rst-client/src/assets.rs +++ b/games/rstnode/rst-client/src/assets.rs @@ -12,29 +12,14 @@ use std::{ }; use tempfile::tempdir; -pub type Result = std::result::Result; - -#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct URI(String, String); - -impl From<&'static str> for URI { - fn from(s: &'static str) -> Self { - let mut v: Vec<_> = s.split("/").collect(); - Self(v.remove(0).into(), v.remove(0).into()) - } -} +pub use rst_core::loader::Uri; -impl From for URI { - fn from(s: String) -> Self { - let mut v: Vec<_> = s.split("/").collect(); - Self(v.remove(0).into(), v.remove(0).into()) - } -} +pub type Result = std::result::Result; /// Asset loader #[derive(Debug)] pub struct Assets { - inner: BTreeMap, + inner: BTreeMap, } impl Assets { @@ -44,7 +29,7 @@ impl Assets { } } - pub fn find>(&self, u: U) -> Option { + pub fn find>(&self, u: U) -> Option { self.inner.get(&u.into()).map(|i| i.clone()) } diff --git a/games/rstnode/rst-client/src/graphics/entities/mod.rs b/games/rstnode/rst-client/src/graphics/entities/mod.rs index db675f816fb..bb28fdd808d 100644 --- a/games/rstnode/rst-client/src/graphics/entities/mod.rs +++ b/games/rstnode/rst-client/src/graphics/entities/mod.rs @@ -19,7 +19,6 @@ impl<'a> From<&'a Coordinates> for Point2 { } pub struct NodeRndr { - pub loc: Coordinates, pub inner: Arc, } @@ -44,7 +43,6 @@ impl Renderer for NodeRndr { } pub struct LinkRndr { - pub loc: Coordinates, pub inner: Arc, } diff --git a/games/rstnode/rst-client/src/state/mod.rs b/games/rstnode/rst-client/src/state/mod.rs index 45e69eee10b..cd030dcd559 100644 --- a/games/rstnode/rst-client/src/state/mod.rs +++ b/games/rstnode/rst-client/src/state/mod.rs @@ -17,7 +17,7 @@ use crate::{ }; use ggez::{event::EventHandler, graphics, Context, GameResult}; use rst_core::{ - data::{Color, Level, Link, Node, Owner, Player, Upgrade}, + data::{Color, Level, Link, Node, Owner, Player, Position, Upgrade}, io::Io, }; use std::sync::Arc; @@ -51,9 +51,9 @@ impl ClientState { vp: Viewport::new(), input: InputHandle::new(), node1: NodeRndr { - loc: Coordinates(512.0, 512.0), inner: Arc::new(Node { id: 0, + pos: Position { x: 512.0, y: 512.0 }, health: 100.into(), max_health: 100.into(), owner: Owner::Player(Player { @@ -70,9 +70,9 @@ impl ClientState { }), }, node2: NodeRndr { - loc: Coordinates(128.0, 128.0), inner: Arc::new(Node { id: 0, + pos: Position { x: 128.0, y: 128.0 }, health: 100.into(), max_health: 100.into(), owner: Owner::Neutral, diff --git a/games/rstnode/rst-core/src/data.rs b/games/rstnode/rst-core/src/data.rs index 44d4e2a1a45..2b7a13eb637 100644 --- a/games/rstnode/rst-core/src/data.rs +++ b/games/rstnode/rst-core/src/data.rs @@ -14,6 +14,12 @@ use std::{ pub type NodeId = usize; +#[derive(Serialize, Deserialize)] +pub struct Position { + pub x: f32, + pub y: f32, +} + /// A node is a computer on the network graph /// /// It's owned by a player, and has some upgrade state, as well as @@ -22,6 +28,8 @@ pub type NodeId = usize; pub struct Node { /// Each node has a unique ID by which it's addressed pub id: NodeId, + /// The position of this node on the map + pub pos: Position, /// The current health pub health: AtomicU32, /// The max health @@ -95,18 +103,9 @@ pub struct Player { // This is required because atomics can't safely be cloned impl Clone for Player { fn clone(&self) -> Self { - let Self { - ref id, - ref name, - ref color, - ref money, - } = self; - Self { - id: id.clone(), - name: name.clone(), - color: color.clone(), - money: money.load(Ordering::Relaxed).into(), + money: self.money.load(Ordering::Relaxed).into(), + ..self.clone() } } } diff --git a/games/rstnode/rst-core/src/lib.rs b/games/rstnode/rst-core/src/lib.rs index dc1a84f63b5..bbf0e8e5933 100644 --- a/games/rstnode/rst-core/src/lib.rs +++ b/games/rstnode/rst-core/src/lib.rs @@ -30,6 +30,7 @@ pub use _if::GameIf; mod _match; pub use _match::Match; +pub mod loader; pub mod config; pub mod data; pub mod error; @@ -46,3 +47,8 @@ pub mod users; pub mod wire; pub use identity::Identity as Id; + +/// ConvenienceWrapper around RwLock +pub(crate) type Lock = async_std::sync::RwLock; +pub(crate) type LockMap = async_std::sync::RwLock>; +pub(crate) type LockSet = async_std::sync::RwLock>; diff --git a/games/rstnode/rst-core/src/loader.rs b/games/rstnode/rst-core/src/loader.rs new file mode 100644 index 00000000000..13cb3773fbf --- /dev/null +++ b/games/rstnode/rst-core/src/loader.rs @@ -0,0 +1,82 @@ +//! An adaptation of the assets loader from rst-client, but only for +//! maps and unit definitions + +use crate::config::MapCfg; +use serde_yaml; +use std::{ + collections::BTreeMap, + fs::{self, File, OpenOptions}, + io::{Read, Write}, + path::PathBuf, +}; + +/// A unique resource identifier +#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub struct Uri(String, String); + +impl From<&'static str> for Uri { + fn from(s: &'static str) -> Self { + let mut v: Vec<_> = s.split("/").collect(); + Self(v.remove(0).into(), v.remove(0).into()) + } +} + +impl From for Uri { + fn from(s: String) -> Self { + let mut v: Vec<_> = s.split("/").collect(); + Self(v.remove(0).into(), v.remove(0).into()) + } +} + +/// A loader for maps +pub struct MapLoader { + root: PathBuf, + inner: BTreeMap, +} + +impl MapLoader { + pub fn load_path(path: PathBuf) -> Self { + Self { + root: path.clone(), + inner: fs::read_dir(&path) + .unwrap() + .filter_map(|map| { + let map = map.unwrap(); + let name = map.file_name().into_string().unwrap(); + + if map.path().is_dir() { + warn!("Directories in map path will be ignored: {}!", name); + None + } else { + let np = map.path().with_extension(""); + let name = np.file_name().unwrap().to_str().unwrap(); + + debug!("Loading map {}", name); + let mut c = String::new(); + let mut f = File::open(map.path()).unwrap(); + f.read_to_string(&mut c).unwrap(); + + Some((name.into(), serde_yaml::from_str(&c).unwrap())) + } + }) + .collect(), + } + } + + /// Save all maps that are present currently + pub fn save_all(&self) { + self.inner.iter().for_each(|(name, map)| { + let path = self.root.join(format!("{}.rstmap", name)); + let mut f = OpenOptions::new() + .truncate(true) + .create(true) + .write(true) + .open(path.clone()) + .unwrap(); + + debug!("Writing map configuration {}", path.to_str().unwrap()); + let buf = serde_yaml::to_string(&map).unwrap(); + f.write_all(buf.as_bytes()).unwrap(); + }); + } +} diff --git a/games/rstnode/rst-core/src/mapstore.rs b/games/rstnode/rst-core/src/mapstore.rs index 85c5e36ef93..eaacba34f27 100644 --- a/games/rstnode/rst-core/src/mapstore.rs +++ b/games/rstnode/rst-core/src/mapstore.rs @@ -3,6 +3,7 @@ use crate::config::MapCfg; use std::{collections::BTreeMap, fs, path::Path}; +#[deprecated] pub struct MapStore { configs: BTreeMap, } diff --git a/games/rstnode/rst-core/src/net/endpoint.rs b/games/rstnode/rst-core/src/net/endpoint.rs index 0c8e2f91242..63fa1185bca 100644 --- a/games/rstnode/rst-core/src/net/endpoint.rs +++ b/games/rstnode/rst-core/src/net/endpoint.rs @@ -1,7 +1,7 @@ -use crate::{server::Server, Id}; +use crate::{server::Server, wire::Response, Id}; use async_std::{ net::UdpSocket, - sync::{Arc, RwLock}, + sync::{Arc, Receiver, RwLock}, task, }; use std::{ @@ -12,19 +12,33 @@ use std::{ pub struct Endpoint { running: AtomicBool, - socket: UdpSocket, + socket: Arc, bind: String, clients: RwLock>, } pub struct Client {} +pub struct SendHandle { + rx: Receiver<(SocketAddr, Response)>, + socket: Arc, +} + +impl SendHandle { + async fn run(self) { + // Loop until + while let Some((peer, resp)) = self.rx.recv().await { + + } + } +} + impl Endpoint { pub async fn new(bind: &str) -> Arc { let socket = UdpSocket::bind(bind).await.unwrap(); Arc::new(Self { running: true.into(), - socket, + socket: Arc::new(socket), bind: bind.into(), clients: Default::default(), }) @@ -35,6 +49,7 @@ impl Endpoint { self.running.store(false, Ordering::Relaxed); } + /// Start listening for incoming packets pub async fn listen(self: &Arc, serv: Arc) { let mut buf = vec![0; 1024]; diff --git a/games/rstnode/rst-core/src/net/handler.rs b/games/rstnode/rst-core/src/net/handler.rs index aa0ab6a281c..007f0c67b06 100644 --- a/games/rstnode/rst-core/src/net/handler.rs +++ b/games/rstnode/rst-core/src/net/handler.rs @@ -3,15 +3,24 @@ use crate::{ server::Server, wire::{Request, Response}, }; -use async_std::sync::{Receiver, Sender}; +use async_std::sync::{Arc, Receiver, Sender}; +use std::net::SocketAddr; +/// A handler task wrapper to execute pub struct Handler { - tx: Sender, + peer: SocketAddr, + tx: Sender<(SocketAddr, Response)>, + server: Arc, } impl Handler { + pub fn new(peer: SocketAddr, tx: Sender<(SocketAddr, Response)>, server: Arc) -> Self { + Self { peer, tx, server } + } + /// Start a message handler with a handle to send a reply back to the clients - pub fn start(req: Request) { - + pub async fn run(self, req: Request) { + let resp = crate::net::parser::request(req, self.server).await; + self.tx.send((self.peer, resp)).await; } } diff --git a/games/rstnode/rst-core/src/net/mod.rs b/games/rstnode/rst-core/src/net/mod.rs index f60cb3b9766..b9b0a4a3a63 100644 --- a/games/rstnode/rst-core/src/net/mod.rs +++ b/games/rstnode/rst-core/src/net/mod.rs @@ -15,6 +15,6 @@ pub use parser::*; // let serv = Server::new(); // let ep = Endpoint::new("localhost:9999").await; // task::spawn(async move { ep.listen(serv).await }); - +// // // Create a fake client here // } diff --git a/games/rstnode/rst-core/src/server.rs b/games/rstnode/rst-core/src/server.rs index 68fa2a074e3..a550a839639 100644 --- a/games/rstnode/rst-core/src/server.rs +++ b/games/rstnode/rst-core/src/server.rs @@ -12,7 +12,7 @@ use crate::{ game::Action, AuthErr, Lobby, LobbyErr, LobbyId, LobbyUpdate, MatchErr, MatchId, RegErr, Response, UpdateState, User, UserId, }, - GameIf, Match, + GameIf, Lock, LockMap, Match, }; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; @@ -32,7 +32,7 @@ pub enum ServerErr { /// The game's server backend pub struct Server { - matches: BTreeMap>, + matches: LockMap>, users: UserStore, lobbies: LobbyList, } @@ -81,8 +81,8 @@ impl Server { where F: Fn(&mut Vec) -> ServerResult, { - match self.matches.get(&id) { - Some(ref mut m) => cb(&mut m.lock().await.players), + match self.matches.read().await.get(&id) { + Some(ref mut m) => cb(&mut m.write().await.players), None => Err(ServerErr::NoSuchMatch), } } diff --git a/games/rstnode/rst-core/src/users.rs b/games/rstnode/rst-core/src/users.rs index 0c93b83ec1d..ea91b3e6cb1 100644 --- a/games/rstnode/rst-core/src/users.rs +++ b/games/rstnode/rst-core/src/users.rs @@ -2,7 +2,7 @@ use crate::{ wire::{LobbyErr, User, UserId}, - Id, + Id, LockMap, }; use async_std::sync::{Arc, RwLock}; use std::{ @@ -19,7 +19,7 @@ pub struct MetaUser { pub struct UserStore { max: AtomicUsize, - users: RwLock>>, + users: LockMap>, } impl UserStore { diff --git a/games/rstnode/rst-server/src/loader.rs b/games/rstnode/rst-server/src/loader.rs new file mode 100644 index 00000000000..fabc173b6de --- /dev/null +++ b/games/rstnode/rst-server/src/loader.rs @@ -0,0 +1,7 @@ +use rst_core::loader::MapLoader; +use std::path::Path; + +/// Load a set of maps at launch +pub(crate) fn load<'p, P: Into<&'p Path>>(path: P) -> MapLoader { + MapLoader::load_path(path.into().to_path_buf()) +} diff --git a/games/rstnode/rst-server/src/main.rs b/games/rstnode/rst-server/src/main.rs index fbdd33bb864..2766f1f3c97 100644 --- a/games/rstnode/rst-server/src/main.rs +++ b/games/rstnode/rst-server/src/main.rs @@ -6,6 +6,7 @@ #[macro_use] extern crate tracing; +pub(crate) mod loader; pub(crate) mod constants; pub(crate) mod log;