diff options
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rwxr-xr-x | clientinet.py | 57 | ||||
| -rw-r--r-- | src/gameserver.rs | 97 | ||||
| -rw-r--r-- | src/main.rs | 15 | ||||
| -rw-r--r-- | src/server/gameserver.rs | 1 | ||||
| -rw-r--r-- | src/simpleworld.rs | 74 |
6 files changed, 198 insertions, 48 deletions
@@ -12,4 +12,4 @@ nix = "0.13" libc = "0.2" users = "0.8" json = "0.11.13" - +specs = "0.14.3" diff --git a/clientinet.py b/clientinet.py new file mode 100755 index 0000000..f4f4887 --- /dev/null +++ b/clientinet.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 + +import socket +import sys +import threading +import json +import getpass + + +def send(sock, msg): + length = len(msg) + header = length.to_bytes(4, byteorder="big") + totalmsg = header + msg + sock.sendall(totalmsg) + +def receive(sock): + header = recvall(sock, 4) #sock.recv(4) + length = int.from_bytes(header, byteorder="big") + return recvall(sock, length) + +def recvall(sock, length): + chunks = [] + bytes_recd = 0 + while bytes_recd < length: + chunk = sock.recv(min(length - bytes_recd, 4096)) + if chunk == b'': + break + #raise RuntimeError("socket connection broken") + chunks.append(chunk) + bytes_recd = bytes_recd + len(chunk) + return b''.join(chunks) + + + +sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +sock.connect(("localhost", 1234)) + +def listen(): + while True: + d = receive(sock) + if len(d) == 0: + print("Connection closed by server", file=sys.stdout) + return + print(str(d, "utf-8")) + +threading.Thread(target=listen, daemon=True).start() + +if len(sys.argv) >= 2: + name = sys.argv[1] +else: + name = getpass.getuser() +print(name) + +send(sock, bytes(json.dumps(["name", name]), "utf-8")) + +for line in sys.stdin: + send(sock, bytes(json.dumps(["chat", line.strip()]), "utf-8")) diff --git a/src/gameserver.rs b/src/gameserver.rs index 76ffbd6..2412e28 100644 --- a/src/gameserver.rs +++ b/src/gameserver.rs @@ -9,81 +9,98 @@ use json::JsonValue; use super::server::Server; -pub enum Message { +enum Message { Name(String), Chat(String), - Input, + Input(JsonValue), Invalid(String) } -pub struct GameServer<T: Server> { - players: HashMap<usize, String>, - connections: HashMap<String, usize>, - server: T +pub enum Action { + Join(String), + Leave(String), + Input(String, JsonValue) } -impl<T: Server> GameServer<T> { - pub fn new(server: T) -> GameServer<T> { +pub struct GameServer { + players: HashMap<(usize, usize), String>, + connections: HashMap<String, (usize, usize)>, + servers: Vec<Box<Server>> +} + +impl GameServer { + pub fn new(servers: Vec<Box<Server>>) -> GameServer { GameServer { players: HashMap::new(), connections: HashMap::new(), - server + servers } } - pub fn update(&mut self) { - self.accept_connections(); - self.receive_messages(); - } - - fn accept_connections(&mut self) { - let _joined = self.server.accept_pending_connections(); - } - - fn receive_messages(&mut self) { + pub fn update(&mut self) -> Vec<Action>{ + for server in self.servers.iter_mut(){ + let _ = server.accept_pending_connections(); + } - let (messages, left) = self.server.recv_pending_messages(); - for (id, message) in messages { - self.handle_message(id, parse_message(&message)); + let mut actions: Vec<Action> = Vec::new(); + let mut input = Vec::new(); + for (serverid, server) in self.servers.iter_mut().enumerate(){ + let (messages, left) = server.recv_pending_messages(); + input.push((serverid, messages, left)); } - for id in left { - self.remove_connection(id); + for (serverid, messages, left) in input { + for (id, message) in messages { + let r = self.handle_message((serverid, id), parse_message(&message)); + if let Some(action) = r { + actions.push(action); + } + } + for id in left { + if let Some(name) = self.players.remove(&(serverid, id)){ + self.connections.remove(&name); + self.broadcast_message(&format!("{} disconnected", name)); + actions.push(Action::Leave(name.clone())); + } + } } + actions } - fn send_error(&mut self, id: usize, errname: &str, err_text: &str) -> Result<(), io::Error>{ - self.server.send(id, &json::stringify(json::array!["error", errname, err_text])) + fn send_error(&mut self, (serverid, connectionid): (usize, usize), errname: &str, err_text: &str) -> Result<(), io::Error>{ + self.servers[serverid].send(connectionid, &json::stringify(json::array!["error", errname, err_text])) } pub fn broadcast_message(&mut self, text: &str){ println!("{}", text); let jsontext = json::stringify(json::array!["message", text]); - for (id, _name) in &self.players { - let _ = self.server.send(*id, &jsontext); + for ((serverid, id), _name) in &self.players { + let _ = self.servers[*serverid].send(*id, &jsontext); } } - pub fn handle_message(&mut self, id: usize, msg: Message) { + fn handle_message(&mut self, (serverid, connectionid): (usize, usize), msg: Message) -> Option<Action> { + let id = (serverid, connectionid); match msg { Message::Name(name) => { let (firstchar, username) = name.split_at(1); if firstchar == "~"{ - if Some(username.to_string()) != self.server.get_name(id) { + if Some(username.to_string()) != self.servers[serverid].get_name(connectionid) { let _ = self.send_error(id, "invalidname", &format!("A tilde name must match your username")); - return; + return None; } } if self.players.contains_key(&id) { let _ = self.send_error(id, "invalidaction", &format!("You can not change your name")); - return; + return None; } if self.connections.contains_key(&name) { let _ = self.send_error(id, "nametaken", &format!("Another connections to this player exists already")); - return; + return None; } self.broadcast_message(&format!("{} connected", name)); self.players.insert(id, name.clone()); - self.connections.insert(name, id); + self.connections.insert(name.clone(), id); + Some(Action::Join(name)) } Message::Chat(text) => { if let Some(name) = self.players.get(&id) { @@ -91,20 +108,16 @@ impl<T: Server> GameServer<T> { } else { let _ = self.send_error(id, "invalidaction", &format!("Set a name before you send other messages")); } + None } - Message::Input => { () } + Message::Input(_) => { None } Message::Invalid(text) => { let _ = self.send_error(id, "invalidmessage", &format!("Invalid: {}", text)); + None } } } - pub fn remove_connection(&mut self, id: usize) { - if let Some(name) = self.players.remove(&id){ - self.connections.remove(&name); - self.broadcast_message(&format!("{} disconnected", name)); - } - } } @@ -133,7 +146,7 @@ fn parse_message(msg: &str) -> Message { } "input" => { - Message::Input + Message::Input(arr[1].clone()) } _ => { Message::Invalid(format!("unknown messsage type {:?}", msgtype).to_string()) diff --git a/src/main.rs b/src/main.rs index ff60460..a9cd76b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,25 +3,32 @@ use std::thread::sleep; use std::time::Duration; use std::path::Path; +// use std::net::SocketAddr; pub mod server; pub mod gameserver; +pub mod simpleworld; use self::gameserver::GameServer; use self::server::unixserver::UnixServer; +use self::server::tcpserver::TcpServer; +use self::server::Server; fn main() { -// let addr = "127.0.0.1:1234".parse().unwrap(); let addr = Path::new("\0rustifarm"); + let unixserver = UnixServer::new(&addr).expect("binding unix server failed"); - let socketserver = UnixServer::new(&addr).expect("binding server failed"); + let addr = "127.0.0.1:1234".parse().unwrap(); + let inetserver = TcpServer::new(&addr).expect("binding inet server failed"); - let mut gameserver = GameServer::new(socketserver); - println!("listening on {:?}", addr); + let servers: Vec<Box<Server>> = vec![Box::new(unixserver), Box::new(inetserver)]; + let mut gameserver = GameServer::new(servers); + +// println!("listening on {:?}", addr); // let mut players: HashMap<usize, String> = HashMap::new(); diff --git a/src/server/gameserver.rs b/src/server/gameserver.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/server/gameserver.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/simpleworld.rs b/src/simpleworld.rs new file mode 100644 index 0000000..1621ee2 --- /dev/null +++ b/src/simpleworld.rs @@ -0,0 +1,74 @@ + +use std::collections::HashMap; +use std::collections::HashSet; + +#[derive(PartialEq, Eq, Hash, Clone, Copy)] +struct Pos (i32, i32); + + +struct Room { + objects :HashMap<Pos, HashSet<GameObject>>, + pub area :(Pos, Pos), + players :HashMap<String, GameObject> +} + + +impl Room { + + pub fn new(area :(Pos, Pos)) -> Room { + Room { + objects: HashMap::new(), + area: area, + players: HashMap::new() + } + } + + + pub fn get_sprites(&self, pos :&Pos) -> Vec<String> { + match self.objects.get(pos) { + Some(objs) => {objs.iter().map(|o| o.sprite.clone()).collect()} + None => {Vec::new()} + } + } + +// let mut sprites :Vec<String> = Vec::new(); +// for maybe_obj in self.objects.get((x, y)) +// sprites.push + + + pub fn draw(&self) -> (Vec<usize>, Vec<Vec<String>>) { + let (minp, maxp) = &self.area; + let Pos(xmin, ymin) = *minp; + let Pos(xmax, ymax) = *maxp; + let width = xmax - xmin; + let height = ymax - ymin; + let size = width * height; + let mut values :Vec<usize>= Vec::with_capacity(size as usize); + let mut mapping = Vec::with_capacity(size as usize); + for y in ymin..ymax { + for x in xmin..xmax { + values.push(mapping.len()); + mapping.push(self.get_sprites(&Pos(x, y))); + } + } + return (values, mapping) + } +} + + +struct GameObject { + pos :Pos, +// name :&str, + sprite :String +} + +impl GameObject { + + pub fn new(sprite :&str, pos :Pos) -> GameObject { + GameObject { + pos: pos, + sprite: sprite.to_string() + } + } + +} |
