summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2020-01-27 21:15:07 +0100
committertroido <troido@protonmail.com>2020-01-27 21:15:07 +0100
commit599d7dc27df5e5ba37ef622d520399d7ca331425 (patch)
tree14f540fb9d186d11dedbea40e731ff2e2db2cf44
parent62c810b6f8ef7c3feca62637b8361a3386fa43d8 (diff)
started using specs for a room
-rw-r--r--Cargo.toml4
-rw-r--r--src/gameserver.rs49
-rw-r--r--src/main.rs80
-rw-r--r--src/room.rs199
-rw-r--r--src/simpleworld.rs23
5 files changed, 333 insertions, 22 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 27af7a0..47fbf31 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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()
}
}