rstnode: add basic map i/o mechanism for server and client

wip/yesman
Katharina Fey 3 years ago
parent 837a0ca643
commit 2f401b176b
Signed by: kookie
GPG Key ID: 90734A9E619C8A6C
  1. 23
      games/rstnode/rst-client/src/assets.rs
  2. 2
      games/rstnode/rst-client/src/graphics/entities/mod.rs
  3. 6
      games/rstnode/rst-client/src/state/mod.rs
  4. 21
      games/rstnode/rst-core/src/data.rs
  5. 6
      games/rstnode/rst-core/src/lib.rs
  6. 82
      games/rstnode/rst-core/src/loader.rs
  7. 1
      games/rstnode/rst-core/src/mapstore.rs
  8. 23
      games/rstnode/rst-core/src/net/endpoint.rs
  9. 17
      games/rstnode/rst-core/src/net/handler.rs
  10. 2
      games/rstnode/rst-core/src/net/mod.rs
  11. 8
      games/rstnode/rst-core/src/server.rs
  12. 4
      games/rstnode/rst-core/src/users.rs
  13. 7
      games/rstnode/rst-server/src/loader.rs
  14. 1
      games/rstnode/rst-server/src/main.rs

@ -12,29 +12,14 @@ use std::{
};
use tempfile::tempdir;
pub type Result<T> = std::result::Result<T, LoadError>;
#[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<String> 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<T> = std::result::Result<T, LoadError>;
/// Asset loader
#[derive(Debug)]
pub struct Assets {
inner: BTreeMap<URI, Image>,
inner: BTreeMap<Uri, Image>,
}
impl Assets {
@ -44,7 +29,7 @@ impl Assets {
}
}
pub fn find<U: Into<URI>>(&self, u: U) -> Option<Image> {
pub fn find<U: Into<Uri>>(&self, u: U) -> Option<Image> {
self.inner.get(&u.into()).map(|i| i.clone())
}

@ -19,7 +19,6 @@ impl<'a> From<&'a Coordinates> for Point2<f32> {
}
pub struct NodeRndr {
pub loc: Coordinates,
pub inner: Arc<Node>,
}
@ -44,7 +43,6 @@ impl Renderer for NodeRndr {
}
pub struct LinkRndr {
pub loc: Coordinates,
pub inner: Arc<Link>,
}

@ -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,

@ -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()
}
}
}

@ -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<T> = async_std::sync::RwLock<T>;
pub(crate) type LockMap<K, V> = async_std::sync::RwLock<std::collections::BTreeMap<K, V>>;
pub(crate) type LockSet<T> = async_std::sync::RwLock<std::collections::BTreeSet<T>>;

@ -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<String> 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<String, MapCfg>,
}
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();
});
}
}

@ -3,6 +3,7 @@
use crate::config::MapCfg;
use std::{collections::BTreeMap, fs, path::Path};
#[deprecated]
pub struct MapStore {
configs: BTreeMap<String, MapCfg>,
}

@ -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<UdpSocket>,
bind: String,
clients: RwLock<BTreeMap<Id, Client>>,
}
pub struct Client {}
pub struct SendHandle {
rx: Receiver<(SocketAddr, Response)>,
socket: Arc<UdpSocket>,
}
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<Self> {
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<Self>, serv: Arc<Server>) {
let mut buf = vec![0; 1024];

@ -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<Response>,
peer: SocketAddr,
tx: Sender<(SocketAddr, Response)>,
server: Arc<Server>,
}
impl Handler {
pub fn new(peer: SocketAddr, tx: Sender<(SocketAddr, Response)>, server: Arc<Server>) -> 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;
}
}

@ -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
// }

@ -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<MatchId, Mutex<Match>>,
matches: LockMap<MatchId, Lock<Match>>,
users: UserStore,
lobbies: LobbyList,
}
@ -81,8 +81,8 @@ impl Server {
where
F: Fn(&mut Vec<Player>) -> ServerResult<Response>,
{
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),
}
}

@ -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<BTreeMap<UserId, Arc<MetaUser>>>,
users: LockMap<UserId, Arc<MetaUser>>,
}
impl UserStore {

@ -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())
}

@ -6,6 +6,7 @@
#[macro_use]
extern crate tracing;
pub(crate) mod loader;
pub(crate) mod constants;
pub(crate) mod log;

Loading…
Cancel
Save