diff options
| -rw-r--r-- | Cargo.toml | 4 | ||||
| -rw-r--r-- | src/gameserver.rs | 49 | ||||
| -rw-r--r-- | src/main.rs | 80 | ||||
| -rw-r--r-- | src/room.rs | 199 | ||||
| -rw-r--r-- | src/simpleworld.rs | 23 |
5 files changed, 333 insertions, 22 deletions
@@ -11,5 +11,5 @@ slab = "0.4.2" nix = "0.13" libc = "0.2" users = "0.8" -json = "0.11.13" -specs = "0.14.3" +json = "0.12.1" +specs = { version = "0.15.1", features = ["specs-derive"] } diff --git a/src/gameserver.rs b/src/gameserver.rs index 2412e28..3a63dc4 100644 --- a/src/gameserver.rs +++ b/src/gameserver.rs @@ -9,6 +9,7 @@ use json::JsonValue; use super::server::Server; +#[derive(Debug)] enum Message { Name(String), Chat(String), @@ -16,6 +17,7 @@ enum Message { Invalid(String) } +#[derive(Debug)] pub enum Action { Join(String), Leave(String), @@ -25,11 +27,11 @@ pub enum Action { pub struct GameServer { players: HashMap<(usize, usize), String>, connections: HashMap<String, (usize, usize)>, - servers: Vec<Box<Server>> + servers: Vec<Box<dyn Server>> } impl GameServer { - pub fn new(servers: Vec<Box<Server>>) -> GameServer { + pub fn new(servers: Vec<Box<dyn Server>>) -> GameServer { GameServer { players: HashMap::new(), connections: HashMap::new(), @@ -71,19 +73,41 @@ impl GameServer { } pub fn broadcast_message(&mut self, text: &str){ - println!("{}", text); - let jsontext = json::stringify(json::array!["message", text]); + println!("m {}", text); + self.broadcast_json(json::array!["message", text, ""]); + } + + pub fn broadcast_json(&mut self, value: JsonValue){ + let jsontext = json::stringify(value); for ((serverid, id), _name) in &self.players { let _ = self.servers[*serverid].send(*id, &jsontext); } } + pub fn send(&mut self, playername: &str, value: JsonValue) -> Result<(), io::Error> { + let jsontext = json::stringify(value); + match self.connections.get(playername) { + Some((serverid, id)) => { + self.servers[*serverid].send(*id, &jsontext) + } + None => Err(io::Error::new(io::ErrorKind::Other, "unknown player name")) + } + } + fn handle_message(&mut self, (serverid, connectionid): (usize, usize), msg: Message) -> Option<Action> { let id = (serverid, connectionid); match msg { Message::Name(name) => { + if name.len() > 256 { + let _ = self.send_error(id, "invalidname", "A name can not be longer than 256 bytes"); + return None + } + if name.len() == 0 { + let _ = self.send_error(id, "invalidname", "A name must have at least one character"); + return None + } let (firstchar, username) = name.split_at(1); - if firstchar == "~"{ + if firstchar == "~" { 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 None; @@ -103,14 +127,23 @@ impl GameServer { Some(Action::Join(name)) } Message::Chat(text) => { - if let Some(name) = self.players.get(&id) { + if let Some(nameref) = self.players.get(&id) { + let name = nameref.clone(); self.broadcast_message(&format!("{}: {}", name, text)); } else { let _ = self.send_error(id, "invalidaction", &format!("Set a name before you send other messages")); } None } - Message::Input(_) => { None } + Message::Input(inp) => { + if let Some(nameref) = self.players.get(&id) { + let name = nameref.clone(); + Some(Action::Input(name, inp)) + } else { + let _ = self.send_error(id, "invalidaction", &format!("Set a name before you send other messages")); + None + } + } Message::Invalid(text) => { let _ = self.send_error(id, "invalidmessage", &format!("Invalid: {}", text)); None @@ -139,7 +172,7 @@ fn parse_message(msg: &str) -> Message { } "chat" => { if let Some(text) = arr[1].as_str(){ - Message::Chat(text.to_string()) + Message::Chat(text.escape_debug().to_string()) } else { Message::Invalid("chat text is not a string".to_string()) } diff --git a/src/main.rs b/src/main.rs index a9cd76b..b6ec8b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,12 +7,16 @@ use std::path::Path; pub mod server; pub mod gameserver; -pub mod simpleworld; +// pub mod simpleworld; +pub mod room; use self::gameserver::GameServer; use self::server::unixserver::UnixServer; use self::server::tcpserver::TcpServer; use self::server::Server; +// use self::simpleworld::{Room, Pos, GameObject}; + +use json; fn main() { @@ -25,17 +29,87 @@ fn main() { let inetserver = TcpServer::new(&addr).expect("binding inet server failed"); - let servers: Vec<Box<Server>> = vec![Box::new(unixserver), Box::new(inetserver)]; + let servers: Vec<Box<dyn 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(); +// let (mut world, dispatcher) = room::make_room((32, 32)); + + + let mut room = room::Room::new((32, 32)); +// dispatcher.dispatch(&mut world); +// world.maintain(); + +// let mut world = generate_world(32, 32); + loop { - gameserver.update(); + let _actions = gameserver.update(); + room.update(); + let (field, mapping) = room.view(); + let updatemsg = create_update_message(room.get_size(), field, mapping); +// dispatcher.dispatch(&mut world); +// world.maintain(); +// let topview = *world.fetch::<TopView>(); + let _ = gameserver.broadcast_json(updatemsg); +// update(&mut gameserver, &mut world); sleep(Duration::from_millis(100)); } } +// fn generate_world(width: i32, height: i32) -> Room { +// +// let mut world = Room::new((Pos(0,0), Pos(width, height))); +// let grass = GameObject::new("grass1"); +// let wall = GameObject::new("wall"); +// for x in 0..width { +// world.add_obj(Pos(x, 0), wall.clone()); +// world.add_obj(Pos(x, height -1), wall.clone()); +// } +// for y in 1..height { +// world.add_obj(Pos(0, y), wall.clone()); +// world.add_obj(Pos(width -1, y), wall.clone()); +// } +// for x in 10..20 { +// for y in 15 .. 25 { +// let pos = Pos(x, y); +// world.add_obj(pos, grass.clone()); +// } +// } +// world +// } + + +fn create_update_message((width, height): (i32, i32), field: Vec<usize>, mapping: Vec<Vec<String>>) -> json::JsonValue { + let mut updatemsg: json::JsonValue = json::array![ + "world", + json::array![ + json::array![ + "field", + json::object!{ + "width" => width, + "height" => height, +// "field" => jfield, +// "mapping" => json::from(mapping) + } + ] + ] + ]; + updatemsg[1][0][1]["field"] = json::from(field); + updatemsg[1][0][1]["mapping"] = json::from(mapping); + updatemsg +} + +// fn update(gameserver: &mut GameServer, world: &mut Room) { +// let actions = gameserver.update(); +// for action in actions { +// println!("a {:?}", action); +// } +// let (_start, Pos(width, height)) = world.area; +// let (field, mapping) = world.draw(); +// // let jfield = json::from(field); +// let _ = gameserver.broadcast_json(updatemsg); +// } diff --git a/src/room.rs b/src/room.rs new file mode 100644 index 0000000..4c1b291 --- /dev/null +++ b/src/room.rs @@ -0,0 +1,199 @@ + +use std::collections::HashMap; +// use std::collections::HashSet; +// use std::ops::Deref; + +use specs::{ + VecStorage, + Component, + System, + World, + WorldExt, + Builder, + Join, + ReadStorage, + DispatcherBuilder, + Dispatcher, + Write +}; + +struct EntityId(usize); + +#[derive(Component, Debug, Hash, PartialEq, Eq, Clone, Copy)] +#[storage(VecStorage)] +struct Position { + x: i32, + y: i32 +} + +#[derive(Component, Debug)] +#[storage(VecStorage)] +struct Visible { + sprite: String, + height: f32 +} + +#[derive(Default)] +struct Size (i32, i32); + + +struct Draw; + +impl <'a> System<'a> for Draw { + + type SystemData = (ReadStorage<'a, Position>, ReadStorage<'a, Visible>, Write<'a, TopView>); + + fn run(&mut self, (pos, vis, mut view): Self::SystemData) { + view.cells.clear(); + for (pos, vis) in (&pos, &vis).join(){ + if pos.x >= 0 && pos.y >= 0 && pos.x < view.width && pos.y < view.height { + view.cells.entry(*pos).or_insert(Vec::new()).push(vis.sprite.clone()); + } + } + } +} + +#[derive(Default)] +struct TopView { + width: i32, + height: i32, + cells: HashMap<Position, Vec<String>> +} + + +pub struct Room<'a, 'b> { + world: World, + dispatcher: Dispatcher<'a, 'b> +} + +impl <'a, 'b>Room<'a, 'b> { + + pub fn new(size: (i32, i32)) -> Room<'a, 'b> { + let (width, height) = size; + let mut world = World::new(); + world.register::<Position>(); + world.register::<Visible>(); + world.insert(Size(width, height)); + world.insert(TopView{width: width, height: height, cells: HashMap::new()}); + + let dispatcher = DispatcherBuilder::new() + .with(Draw, "draw", &[]) + .build(); + + gen_world(&mut world); + + Room { + world, + dispatcher + } + } + + pub fn view(&self) -> (Vec<usize>, Vec<Vec<String>>) { + let tv = &*self.world.fetch::<TopView>(); + let width = tv.width; + let height = tv.height; +// let TopView{width: width, height: height, cells: cells} = ; + let size = width * height; + let mut values :Vec<usize> = Vec::with_capacity(size as usize); + let mut mapping: Vec<Vec<String>> = Vec::with_capacity(size as usize); + for y in 0..height { + for x in 0..width { +// values.push(mapping.len()); + let sprites = match tv.cells.get(&Position{x: x, y: y}) { + Some(sprites) => {sprites.to_vec()} + None => {vec![]} + }; + values.push( + match mapping.iter().position(|x| x == &sprites) { + Some(index) => { + index + } + None => { + mapping.push(sprites); + mapping.len() - 1 + } + } + ) + } + } + (values, mapping) + } + + pub fn update(&mut self) { + self.dispatcher.dispatch(&mut self.world); + self.world.maintain(); + } + + pub fn get_size(&self) -> (i32, i32) { + let Size(width, height) = *self.world.fetch::<Size>(); + (width, height) + } +} + +fn gen_world(world: &mut World){ + + let Size(width, height) = *world.fetch::<Size>(); + for x in 0..width { + world.create_entity().with(Position{x: x, y: 0}).with(Visible{sprite: "wall".to_string(), height: 1.0}).build(); + world.create_entity().with(Position{x: x, y: height - 1}).with(Visible{sprite: "wall".to_string(), height: 1.0}).build(); + } + for y in 1..height-1 { + world.create_entity().with(Position{x: 0, y: y}).with(Visible{sprite: "wall".to_string(), height: 1.0}).build(); + world.create_entity().with(Position{x: width - 1, y: y}).with(Visible{sprite: "wall".to_string(), height: 1.0}).build(); + } +} + +// pub fn make_room<'a, 'b>(size: (i32, i32)) -> (World, Dispatcher<'a, 'b>){ +// let (width, height) = size; +// let mut world = World::new(); +// world.register::<Position>(); +// world.register::<Visible>(); +// world.insert(Size(width, height)); +// world.insert(TopView{width: width, height: height, cells: HashMap::new()}); +// +// +// +// let mut dispatcher = DispatcherBuilder::new() +// .with(Draw, "draw", &[]) +// .build(); +// +// +// gen_world(&mut world); +// +// (world, dispatcher) +// } + +// pub fn view_room(world :&World) -> (Vec<usize>, Vec<Vec<String>>) { +// let TopView{width: width, height: height, cells: cells} = *world.fetch::<TopView>(); +// 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 0..height { +// for x in 0..width { +// values.push(mapping.len()); +// mapping.push(match cells.get(Position{x: x, y: y}) { +// Some(sprites) => {sprites} +// None => {vec![]} +// }); +// } +// } +// return (values, mapping) +// +// } + +// struct Room { +// entities: Entities, +// width: u32, +// height: u32, +// ground: HashMap<(u32, u32), GroundTile> +// } +// +// struct Entities { +// components: HashMap<EntityId, Box<Component>>, +// systems: HashMap<EntityId, Box<System>> +// } +// +// +// struct GroundTile { +// entities: HashSet<EntityId> +// } diff --git a/src/simpleworld.rs b/src/simpleworld.rs index 1621ee2..5b89339 100644 --- a/src/simpleworld.rs +++ b/src/simpleworld.rs @@ -1,13 +1,12 @@ use std::collections::HashMap; -use std::collections::HashSet; #[derive(PartialEq, Eq, Hash, Clone, Copy)] -struct Pos (i32, i32); +pub struct Pos(pub i32, pub i32); -struct Room { - objects :HashMap<Pos, HashSet<GameObject>>, +pub struct Room { + objects :HashMap<Pos, Vec<GameObject>>, pub area :(Pos, Pos), players :HashMap<String, GameObject> } @@ -31,6 +30,11 @@ impl Room { } } + pub fn add_obj(&mut self, pos :Pos, obj :GameObject) { + let place = self.objects.entry(pos).or_insert(Vec::new()); + place.push(obj); + } + // let mut sprites :Vec<String> = Vec::new(); // for maybe_obj in self.objects.get((x, y)) // sprites.push @@ -43,7 +47,7 @@ impl Room { 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 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 { @@ -56,17 +60,18 @@ impl Room { } -struct GameObject { - pos :Pos, +#[derive(Clone)] +pub struct GameObject { +// pos :Pos, // name :&str, sprite :String } impl GameObject { - pub fn new(sprite :&str, pos :Pos) -> GameObject { + pub fn new(sprite :&str) -> GameObject { GameObject { - pos: pos, +// pos: pos, sprite: sprite.to_string() } } |
