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 } } |