From 473dc29e540cb1ed332b6f2895f6f6efe2d60e65 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Tue, 4 Jun 2024 19:37:46 +0200 Subject: spectator see names --- src/bot/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/config.rs | 3 ++- src/main.rs | 2 ++ src/spectate/index.html | 1 + src/spectate/main.ts | 29 ++++++++++++++++++++++++++--- src/spectate/server.rs | 30 ++++++++++++++++++++++++++++++ src/spectate/style.css | 4 ++++ 7 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/spectate/style.css (limited to 'src') diff --git a/src/bot/mod.rs b/src/bot/mod.rs index 71c659f..17472d2 100644 --- a/src/bot/mod.rs +++ b/src/bot/mod.rs @@ -1 +1,48 @@ -pub async fn spawn_bots() {} +use crate::{game::protocol::Direction, State}; +use log::debug; +use rand::{seq::IteratorRandom, thread_rng}; +use serde::Deserialize; +use std::{ops::DerefMut, sync::Arc}; +use tokio::spawn; + +#[derive(Deserialize, Clone)] +pub struct Config { + amount: usize, +} + +pub async fn spawn_bots(config: Config, state: Arc) { + for i in 0..config.amount { + spawn(bot(config.clone(), state.clone(), format!("bot{i}"))); + } +} + +async fn bot(_config: Config, state: Arc, name: String) { + let mut ticks = state.tick.subscribe(); + let id = { + let mut g = state.players.write().await; + let mut id = 0; + while g.contains_key(&id) { + id += 1; + } + g.insert(id, name.clone()); + id + }; + let mut possible = Vec::new(); + while let Ok(_) = ticks.recv().await { + let mut g = state.game.write().await; + let g = g.deref_mut(); + if let Some((dir, head, _)) = g.heads.get_mut(&id) { + possible.clear(); + for d in Direction::ALL { + if g.map[*head + d.vector()].is_none() { + possible.push(d) + } + } + *dir = *possible + .iter() + .choose(&mut thread_rng()) + .unwrap_or(&Direction::Up); + debug!(name:?, dir:?; ""); + } + } +} diff --git a/src/config.rs b/src/config.rs index 678074e..eea7991 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,4 @@ -use crate::{game, spectate}; +use crate::{bot, game, spectate}; use anyhow::{anyhow, Result}; use serde::Deserialize; use std::fs::read_to_string; @@ -7,6 +7,7 @@ use std::fs::read_to_string; pub struct Config { pub game: game::Config, pub spectate: spectate::Config, + pub bot: bot::Config, } impl Config { diff --git a/src/main.rs b/src/main.rs index 2e379fc..d2f22ff 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ use gpn_tron2::{ + bot::spawn_bots, config::Config, game::{server::game_server, Game}, spectate::server::spectate_server, @@ -18,6 +19,7 @@ async fn main() -> anyhow::Result<()> { chat: broadcast::channel(16).0, }); spawn(spectate_server(config.spectate, state.clone())); + spawn_bots(config.bot, state.clone()).await; game_server(config.game, state.clone()).await?; Ok(()) } diff --git a/src/spectate/index.html b/src/spectate/index.html index 94ef698..394b780 100644 --- a/src/spectate/index.html +++ b/src/spectate/index.html @@ -4,6 +4,7 @@ GPN Tron + diff --git a/src/spectate/main.ts b/src/spectate/main.ts index 422a2c6..ea84924 100644 --- a/src/spectate/main.ts +++ b/src/spectate/main.ts @@ -70,7 +70,7 @@ function redraw() { } ctx.lineCap = "round" ctx.lineJoin = "round" - if (snake.dead) ctx.lineWidth = tick_lerp(0.6, 0) + if (snake.dead) ctx.lineWidth = tick_lerp(0.6, 0.001) else ctx.lineWidth = 0.6; ctx.strokeStyle = snake.color ctx.stroke() @@ -78,6 +78,26 @@ function redraw() { ctx.restore() } ctx.restore() + + ctx.save() + ctx.translate(scale / 2, scale / 4) + for (const [xo, yo] of [[0, 0], [-size * scale, 0], [size * scale, 0], [0, -size * scale], [0, size * scale]]) { + ctx.save() + ctx.translate(xo, yo) + for (const snake of snakes.values()) { + const p = snake.parts[snake.parts.length - 1]; + if (!p) continue + ctx.font = "30px sans-serif" + if (snake.dead) ctx.fillStyle = `rgba(1,1,1,${tick_lerp(1, 0)})` + else ctx.fillStyle = "white" + ctx.textAlign = "center" + ctx.textBaseline = "bottom" + ctx.fillText(snake.name, tick_lerp(p.x - p.dx, p.x) * scale, tick_lerp(p.y - p.dy, p.y) * scale) + } + ctx.restore() + } + ctx.restore() + tick_anim += 0.1 tick_anim = Math.min(1, tick_anim) requestAnimationFrame(redraw) @@ -90,10 +110,13 @@ function tick_lerp(f: number, t: number) { function name_color(name: string): string { let hash = 0; for (let i = 0; i < name.length; i++) { - hash = ((hash << 5) - hash) + name.charCodeAt(i); + hash += name.charCodeAt(i); hash |= 0; + hash ^= hash << 13; + hash ^= hash >> 17; + hash ^= hash << 5; } - return `hsl(${hash % 360}deg 100% 50%)`; + return `hsl(${hash % 360}deg 80% 40%)`; } ws.onerror = console.error diff --git a/src/spectate/server.rs b/src/spectate/server.rs index d9d2ef8..3923bc1 100644 --- a/src/spectate/server.rs +++ b/src/spectate/server.rs @@ -36,6 +36,7 @@ pub async fn spectate_server(config: Config, state: Arc) -> Result<()> { let app = Router::new() .route("/", get(index)) .route("/main.js", get(javascript)) + .route("/style.css", get(css)) .route("/events", get(ws_handler)) .with_state(sstate); let listener = tokio::net::TcpListener::bind(config.bind).await.unwrap(); @@ -71,6 +72,35 @@ async fn javascript() -> (HeaderMap, &'static str) { hm.typed_insert(ContentType::from_str("application/javascript").unwrap()); (hm, include_str!(concat!(env!("OUT_DIR"), "/main.js"))) } +#[cfg(debug_assertions)] +async fn css() -> (HeaderMap, String) { + use headers::HeaderMapExt; + use tokio::fs::read_to_string; + let mut hm = HeaderMap::new(); + hm.typed_insert(ContentType::from_str("text/css").unwrap()); + ( + hm, + read_to_string(concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/spectate/style.css" + )) + .await + .unwrap(), + ) +} +#[cfg(not(debug_assertions))] +async fn css() -> (HeaderMap, &'static str) { + use headers::HeaderMapExt; + let mut hm = HeaderMap::new(); + hm.typed_insert(ContentType::from_str("text/css").unwrap()); + ( + hm, + include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/src/spectate/style.css" + )), + ) +} async fn broadcaster(sstate: Arc, state: Arc) { let mut ticks = state.tick.subscribe(); diff --git a/src/spectate/style.css b/src/spectate/style.css new file mode 100644 index 0000000..52711d0 --- /dev/null +++ b/src/spectate/style.css @@ -0,0 +1,4 @@ +canvas { + height: min(100dvh, 70dvw); + float: left; +} -- cgit v1.2.3-70-g09d2