aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-17 01:06:14 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-17 01:06:14 +0200
commitfe164b52e7dd3468e53c8d5d4883b432cce18fbf (patch)
tree2eae77e893c007f314adbb459773fba451238d89
parente37231630488e5b54741d68edc45890a62c5610d (diff)
downloadhurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar
hurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar.bz2
hurrycurry-fe164b52e7dd3468e53c8d5d4883b432cce18fbf.tar.zst
basic movement
-rw-r--r--server/src/main.rs79
-rw-r--r--test-client/main.ts51
-rw-r--r--test-client/util.ts4
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 } }