diff options
| author | metamuffin <metamuffin@disroot.org> | 2024-06-17 01:06:14 +0200 | 
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2024-06-17 01:06:14 +0200 | 
| commit | fe164b52e7dd3468e53c8d5d4883b432cce18fbf (patch) | |
| tree | 2eae77e893c007f314adbb459773fba451238d89 | |
| parent | e37231630488e5b54741d68edc45890a62c5610d (diff) | |
| download | hurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar hurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar.bz2 hurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar.zst | |
basic movement
| -rw-r--r-- | server/src/main.rs | 79 | ||||
| -rw-r--r-- | test-client/main.ts | 51 | ||||
| -rw-r--r-- | test-client/util.ts | 4 | 
3 files changed, 101 insertions, 33 deletions
| diff --git a/server/src/main.rs b/server/src/main.rs index 763ff03b..477595d0 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,6 +1,6 @@  use anyhow::Result;  use futures_util::{SinkExt, StreamExt}; -use log::{debug, info}; +use log::{debug, info, warn};  use std::{sync::Arc, time::Duration};  use tokio::{      io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, @@ -32,14 +32,16 @@ async fn main() -> Result<()> {      {          let game = game.clone();          spawn(async move { -            { -                let mut g = game.write().await; -                while let Some(p) = g.packet_out() { -                    debug!("-> {p:?}"); -                    let _ = tx.send(p); +            loop { +                { +                    let mut g = game.write().await; +                    while let Some(p) = g.packet_out() { +                        debug!("-> {p:?}"); +                        let _ = tx.send(p); +                    }                  } +                sleep(Duration::from_millis(20)).await;              } -            sleep(Duration::from_millis(10)).await;          });      } @@ -54,23 +56,27 @@ async fn main() -> Result<()> {                  spawn(async move {                      write                          .write_all(serde_json::to_string(&PacketC::Joined { id }).unwrap().as_bytes()) -                        .await -                        .unwrap(); -                    write.write_all(b"\n").await.unwrap(); +                        .await?; +                    write.write_all(b"\n").await?;                      while let Ok(packet) = rx.recv().await {                          write                              .write_all(serde_json::to_string(&packet).unwrap().as_bytes()) -                            .await -                            .unwrap(); -                        write.write_all(b"\n").await.unwrap(); +                            .await?; +                        write.write_all(b"\n").await?;                      } +                    Ok::<_, anyhow::Error>(())                  });                  spawn(async move {                      let mut read = BufReader::new(read).lines();                      while let Ok(Some(line)) = read.next_line().await { -                        let packet: PacketS = serde_json::from_str(&line).unwrap(); +                        let Ok(packet): Result<PacketS, _> = serde_json::from_str(&line) else { +                            warn!("invalid json over tcp"); +                            break +                        };                          debug!("<- {id} {packet:?}"); -                        game.write().await.packet_in(id, packet).unwrap(); +                        if let Err(e) = game.write().await.packet_in(id, packet) { +                            warn!("client error: {e}"); +                        }                      }                  });              } @@ -82,26 +88,37 @@ async fn main() -> Result<()> {                  let mut rx = rx.resubscribe();                  info!("{addr} connected via ws");                  spawn(async move { -                    write -                        .send(tokio_tungstenite::tungstenite::Message::Text( -                            serde_json::to_string(&PacketC::Joined { id }).unwrap(), -                        )) -                        .await -                        .unwrap(); +                    if let Err(e) = write.send(tokio_tungstenite::tungstenite::Message::Text( +                        serde_json::to_string(&PacketC::Joined { id }).unwrap(), +                    )).await { +                        warn!("ws error on init: {e}"); +                        return; +                    }                      while let Ok(packet) = rx.recv().await { -                        write -                            .send(tokio_tungstenite::tungstenite::Message::Text( -                                serde_json::to_string(&packet).unwrap(), -                            )) -                            .await -                            .unwrap(); +                        if let Err(e) = write.send(tokio_tungstenite::tungstenite::Message::Text( +                            serde_json::to_string(&packet).unwrap(), +                        )).await { +                            warn!("ws error: {e}"); +                            break; +                        }                      }                  });                  spawn(async move { -                    while let Some(Ok(Message::Text(message))) = read.next().await { -                        let packet: PacketS = serde_json::from_str(&message).unwrap(); -                        debug!("<- {id} {packet:?}"); -                        game.write().await.packet_in(id, packet).unwrap(); +                    while let Some(Ok(message)) = read.next().await { +                        match message { +                            Message::Text(line) => { +                                let Ok(packet): Result<PacketS, _> = serde_json::from_str(&line) else { +                                    warn!("invalid json over ws"); +                                    break +                                }; +                                debug!("<- {id} {packet:?}"); +                                if let Err(e) = game.write().await.packet_in(id, packet) { +                                    warn!("client error: {e}"); +                                } +                            }, +                            Message::Close(_) => break, +                            _ => (), +                        }                      }                  });              } diff --git a/test-client/main.ts b/test-client/main.ts index d093c62e..b9fb1557 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -1,10 +1,11 @@  /// <reference lib="dom" />  import { PacketC, PacketS } from "./protocol.ts"; +import { normalize } from "./util.ts";  let ctx: CanvasRenderingContext2D;  let canvas: HTMLCanvasElement; -let ws: WebSocket +let ws: WebSocket;  document.addEventListener("DOMContentLoaded", () => {      ws = new WebSocket(`${window.location.protocol.endsWith("s:") ? "wss" : "ws"}://${window.location.hostname}:27032/`)      ws.onerror = console.error @@ -23,6 +24,10 @@ document.addEventListener("DOMContentLoaded", () => {      resize()      globalThis.addEventListener("resize", resize)      draw() + +    document.addEventListener("keydown", ev => keyboard(ev, true)) +    document.addEventListener("keyup", ev => keyboard(ev, false)) +    setInterval(tick_update, 1000 / 25);  })  interface Player { x: number; y: number, name: string, rot: number } @@ -31,10 +36,11 @@ interface Item { x: number; y: number }  const items = new Map<number, Item>()  interface Tile { x: number; y: number }  const tiles = new Map<string, Tile>() -let my_id = undefined +let my_id: number = -1  function send(p: PacketS) { ws.send(JSON.stringify(p)) }  function packet(p: PacketC) { +    console.log(p);      if ("joined" in p) {          my_id = p.joined.id      } else if ("add_player" in p) { @@ -55,13 +61,45 @@ function packet(p: PacketC) {      } else console.warn("unknown packet", p);  } +const keys_down = new Set(); +const HANDLED_KEYS = ["KeyW", "KeyA", "KeyS", "KeyD", "Space"] +function keyboard(ev: KeyboardEvent, down: boolean) { +    if (HANDLED_KEYS.includes(ev.code)) ev.preventDefault() +    if (ev.code == "Space") interact() +    if (down) keys_down.add(ev.code) +    else keys_down.delete(ev.code) +} + +function interact() { + +} + +function tick_update() { +    const p = players.get(my_id) +    if (!p) return +} +function frame_update(dt: number) { +    const p = players.get(my_id) +    if (!p) return + +    const input = normalize({ +        x: (+keys_down.has("KeyD") - +keys_down.has("KeyA")), +        y: (+keys_down.has("KeyS") - +keys_down.has("KeyW")) +    }) +    p.x += input.x * dt * 10 +    p.y += input.y * dt * 10 +}  function resize() {      canvas.width = globalThis.innerWidth      canvas.height = globalThis.innerHeight  } +let last_frame = Date.now()  function draw() { +    const now = Date.now() +    frame_update((now - last_frame) / 1000) +    last_frame = now;      if (ws.readyState == ws.CONNECTING) draw_wait("Connecting...")      else if (ws.readyState == ws.CLOSING) draw_wait("Closing...")      else if (ws.readyState == ws.CLOSED) draw_wait("Disconnected") @@ -79,6 +117,8 @@ function draw_wait(text: string) {      ctx.lineWidth = 10      ctx.textAlign = "center"      ctx.textBaseline = "middle" +    ctx.lineJoin = "round" +    ctx.lineCap = "round"      ctx.strokeText(text, canvas.width / 2, canvas.height / 2)      ctx.fillText(text, canvas.width / 2, canvas.height / 2)  } @@ -87,6 +127,11 @@ function draw_ingame() {      ctx.fillStyle = "#111"      ctx.fillRect(0, 0, canvas.width, canvas.height) +    const scale = Math.min(canvas.width, canvas.height) / 10; +    ctx.save() +    ctx.translate(canvas.width / 2, canvas.height / 2) +    ctx.scale(scale, scale) +      for (const [_, player] of players) {          ctx.save()          ctx.translate(player.x, player.y) @@ -95,5 +140,7 @@ function draw_ingame() {          ctx.fillRect(-0.5, -0.5, 1, 1)          ctx.restore()      } + +    ctx.restore()  } diff --git a/test-client/util.ts b/test-client/util.ts new file mode 100644 index 00000000..994e6acf --- /dev/null +++ b/test-client/util.ts @@ -0,0 +1,4 @@ +export interface V2 { x: number, y: number } +export function length(p: V2): number { return Math.sqrt(p.x * p.x + p.y * p.y) } +export function normalize_mut(p: V2) { const l = length(p); if (l == 0) return; p.x /= l; p.y /= l } +export function normalize(p: V2): V2 { let l = length(p); if (l == 0) l = 1; return { x: p.x / l, y: p.y / l } } | 
