Browse Source

Start making it naively multiplayer

Getty Ritter 3 years ago
parent
commit
8814723017
6 changed files with 181 additions and 4 deletions
  1. 5 0
      Cargo.lock
  2. 11 1
      Cargo.toml
  3. 76 0
      src/messages.rs
  4. 0 0
      src/network.rs
  5. 15 3
      src/main.rs
  6. 74 0
      src/server.rs

+ 5 - 0
Cargo.lock

@@ -1552,6 +1552,8 @@ dependencies = [
  "ggez",
  "nalgebra",
  "rand 0.7.3",
+ "serde",
+ "serde_json",
  "specs",
  "specs-derive",
  "specs-system-macro",
@@ -1961,6 +1963,9 @@ name = "serde"
 version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a"
+dependencies = [
+ "serde_derive",
+]
 
 [[package]]
 name = "serde_derive"

+ 11 - 1
Cargo.toml

@@ -4,6 +4,14 @@ version = "0.1.0"
 authors = ["Getty Ritter <samothes@infinitenegativeutility.com>"]
 edition = "2018"
 
+[[bin]]
+name = "promenade"
+path = "src/promenade.rs"
+
+[[bin]]
+name = "prom-server"
+path = "src/server.rs"
+
 [dependencies]
 ggez = "*"
 nalgebra = "*"
@@ -11,4 +19,6 @@ specs = "*"
 specs-derive = "*"
 specs-system-macro = { git = "https://git.infinitenegativeutility.com/getty/specs-system-macro.git" }
 winit = "*"
-rand = "*"
+rand = "*"
+serde = { version = "*", features = [ "derive" ] }
+serde_json = "*"

+ 76 - 0
src/messages.rs

@@ -0,0 +1,76 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Serialize, Deserialize)]
+pub struct Msg {
+    pub nonce: u16,
+    pub command: Command,
+}
+
+#[derive(Serialize, Deserialize)]
+pub enum Command {
+    Hello(String),
+    Goodbye,
+    Update(f32, f32),
+}
+
+impl Msg {
+    pub fn parse<R>(reader: R) -> Option<Msg>
+        where R: std::io::Read
+    {
+        match serde_json::from_reader(reader) {
+            Ok(r) => Some(r),
+            Err(_err) => None,
+        }
+    }
+
+    pub fn from_slice(slice: &[u8]) -> Msg {
+        serde_json::from_slice(slice).unwrap()
+    }
+
+    pub fn emit<W>(&self, writer: W)
+    where W: std::io::Write
+    {
+        serde_json::to_writer(writer, self).unwrap()
+    }
+}
+
+pub struct Connection {
+    nonce: u16,
+    tcp_addr: String,
+    udp_sock: std::net::UdpSocket,
+}
+
+impl Connection {
+    pub fn new(name: &str, host: &str, port: u32) -> Self {
+        let nonce = rand::random();
+        let tcp_addr = format!("{}:{}", host, port);
+        let stream = std::net::TcpStream::connect(&tcp_addr).unwrap();
+
+        Msg {
+            nonce: nonce,
+            command: Command::Hello(name.to_string()),
+        }.emit(stream);
+
+        let udp_addr = format!("{}:{}", host, port+1);
+        let udp_sock = std::net::UdpSocket::bind("0.0.0.0:9898").unwrap();
+        udp_sock.connect(udp_addr);
+        Connection { nonce, tcp_addr, udp_sock }
+    }
+
+    pub fn update(&self, x: f32, y: f32) {
+        let update = Msg {
+            nonce: self.nonce,
+            command: Command::Update(x, y),
+        };
+        let buf = serde_json::ser::to_vec(&update).unwrap();
+        self.udp_sock.send(&buf).unwrap();
+    }
+
+    pub fn goodbye(&self) {
+        let stream = std::net::TcpStream::connect(&self.tcp_addr).unwrap();
+        Msg {
+            nonce: self.nonce,
+            command: Command::Goodbye,
+        }.emit(stream);
+    }
+}

+ 0 - 0
src/network.rs


+ 15 - 3
src/main.rs

@@ -8,6 +8,7 @@ use specs::prelude::*;
 use specs::world::WorldExt;
 
 mod input;
+pub mod messages;
 pub mod util;
 
 const WIDTH: f32 = 600.0;
@@ -18,13 +19,14 @@ struct Game {
 }
 
 impl Game {
-    fn setup() -> Game {
+    fn setup(conn: messages::Connection) -> Game {
         let mut world = specs::World::new();
         world.register::<Pos>();
         world.register::<Vel>();
         world.register::<Solid>();
         world.register::<Controlled>();
         world.insert(input::Input::new());
+        world.insert(conn);
         world
             .create_entity()
             .with(Pos { x: 200.0, y: 200.0 })
@@ -55,6 +57,12 @@ pub struct Controlled;
 #[derive(Component)]
 pub struct Solid;
 
+system! {
+    Transmit(resource conn: messages::Connection, _c: Controlled, p: Pos) {
+        conn.update(p.x, p.y);
+    }
+}
+
 system! {
     Control(resource inp: input::Input, _c: Controlled, mut v: Vel) {
         const ACCEL: f32 = 0.5;
@@ -147,6 +155,7 @@ impl ggez::event::EventHandler for Game {
         Physics.run_now(&self.world);
         Slowdown.run_now(&self.world);
         Move.run_now(&self.world);
+        Transmit.run_now(&self.world);
         Ok(())
     }
 
@@ -159,6 +168,7 @@ impl ggez::event::EventHandler for Game {
         _repeat: bool,
     ) {
         if keycode == winit::VirtualKeyCode::Escape {
+            self.world.read_resource::<messages::Connection>().goodbye();
             ggez::event::quit(ctx);
         }
         input::Input::handle_down(&mut self.world.write_resource(), keycode);
@@ -175,6 +185,7 @@ impl ggez::event::EventHandler for Game {
 }
 
 fn main() -> ggez::GameResult<()> {
+    let connection = messages::Connection::new("foo", "192.168.0.3", 9991);
     let (mut ctx, mut evloop) = ggez::ContextBuilder::new("game", "me")
         .window_mode(ggez::conf::WindowMode {
             width: WIDTH,
@@ -182,6 +193,7 @@ fn main() -> ggez::GameResult<()> {
             ..ggez::conf::WindowMode::default()
         })
         .build()?;
-    let mut game = Game::setup();
-    ggez::event::run(&mut ctx, &mut evloop, &mut game)
+    let mut game = Game::setup(connection);
+    let res = ggez::event::run(&mut ctx, &mut evloop, &mut game);
+    res
 }

+ 74 - 0
src/server.rs

@@ -0,0 +1,74 @@
+use std::collections::HashMap;
+use std::net::TcpListener;
+
+mod messages;
+
+#[derive(Debug)]
+struct Player {
+    name: String,
+    xy: (f32, f32),
+}
+
+#[derive(Debug)]
+struct State {
+    players: HashMap<u16, Player>,
+}
+
+impl State {
+    fn new() -> State {
+        let players = HashMap::new();
+        State { players }
+    }
+
+    fn handle_message(&mut self, msg: messages::Msg) {
+        let nonce = msg.nonce;
+        match msg.command {
+            messages::Command::Hello(name) => {
+                let player = Player { name, xy: (0.0, 0.0) };
+                self.players.insert(nonce, player);
+            }
+            messages::Command::Goodbye => {
+                self.players.remove(&nonce);
+            }
+            messages::Command::Update(x, y) => {
+                if let Some(p) = self.players.get_mut(&nonce) {
+                    p.xy = (x, y);
+                }
+            }
+        }
+    }
+}
+
+fn main() {
+    let (send, recv) = std::sync::mpsc::channel();
+    let udp_send = send.clone();
+    std::thread::spawn(move || {
+        let listener = TcpListener::bind("0.0.0.0:9991").unwrap();
+        loop {
+            match listener.accept() {
+                Ok((sock, _addr)) => {
+                    let msg = match messages::Msg::parse(sock) {
+                        Some(m) => m,
+                        None => continue,
+                    };
+                    send.send(msg).unwrap();
+                },
+                Err(e) => eprintln!("Problem! {:?}", e),
+            }
+        }
+    });
+    std::thread::spawn(move || {
+        let socket = std::net::UdpSocket::bind("0.0.0.0:9992").unwrap();
+        let mut buf = [0;1024];
+        loop {
+            let (amt, _) = socket.recv_from(&mut buf).unwrap();
+            let msg = messages::Msg::from_slice(&buf[..amt]);
+            udp_send.send(msg).unwrap();
+        }
+    });
+    let mut state = State::new();
+    while let Ok(msg) = recv.recv() {
+        state.handle_message(msg);
+        println!("State: {:?}", state);
+    }
+}