diff options
author | metamuffin <metamuffin@disroot.org> | 2024-06-04 19:37:46 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-06-04 19:37:46 +0200 |
commit | 473dc29e540cb1ed332b6f2895f6f6efe2d60e65 (patch) | |
tree | ccd869dab5adece9f9f6a7190ee56fe5ad1c7b3d | |
parent | f39f9840a8d14f35de0d38c9570ae27bacb20119 (diff) | |
download | gpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar gpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar.bz2 gpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar.zst |
spectator see names
-rw-r--r-- | Cargo.lock | 60 | ||||
-rw-r--r-- | Cargo.toml | 5 | ||||
-rw-r--r-- | config.toml | 3 | ||||
-rw-r--r-- | src/bot/mod.rs | 49 | ||||
-rw-r--r-- | src/config.rs | 3 | ||||
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/spectate/index.html | 1 | ||||
-rw-r--r-- | src/spectate/main.ts | 29 | ||||
-rw-r--r-- | src/spectate/server.rs | 30 | ||||
-rw-r--r-- | src/spectate/style.css | 4 |
10 files changed, 175 insertions, 11 deletions
@@ -435,6 +435,7 @@ dependencies = [ "headers", "log", "mime", + "rand 0.9.0-alpha.1", "serde", "serde_json", "tokio", @@ -772,8 +773,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" +dependencies = [ + "rand_chacha 0.9.0-alpha.1", + "rand_core 0.9.0-alpha.1", + "zerocopy", ] [[package]] @@ -783,7 +795,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.0-alpha.1", ] [[package]] @@ -796,6 +818,16 @@ dependencies = [ ] [[package]] +name = "rand_core" +version = "0.9.0-alpha.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9" +dependencies = [ + "getrandom", + "zerocopy", +] + +[[package]] name = "redox_syscall" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1158,7 +1190,7 @@ dependencies = [ "http", "httparse", "log", - "rand", + "rand 0.8.5", "sha1", "thiserror", "url", @@ -1374,3 +1406,23 @@ checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] + +[[package]] +name = "zerocopy" +version = "0.8.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.0-alpha.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] @@ -7,8 +7,8 @@ edition = "2021" tokio = { version = "1.38.0", features = ["full"] } axum = { version = "0.7.5", features = ["ws"] } futures = "0.3.30" -env_logger = "0.11.3" -log = "0.4.21" +env_logger = { version = "0.11.3", features = ["unstable-kv"] } +log = { version = "0.4.21", features = ["kv"] } anyhow = "1.0.86" toml = "0.8.14" serde = { version = "1.0.203", features = ["derive"] } @@ -16,3 +16,4 @@ glam = "0.27.0" serde_json = "1.0.117" headers = "0.4.0" mime = "0.3.17" +rand = "0.9.0-alpha.1" diff --git a/config.toml b/config.toml index 9cdb4c7..7715000 100644 --- a/config.toml +++ b/config.toml @@ -4,3 +4,6 @@ bind = "127.0.0.1:8000" [game] bind = "0.0.0.0:4000" tickrate = 1 + +[bot] +amount = 10 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<State>) { + for i in 0..config.amount { + spawn(bot(config.clone(), state.clone(), format!("bot{i}"))); + } +} + +async fn bot(_config: Config, state: Arc<State>, 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 @@ <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>GPN Tron</title> + <link rel="stylesheet" href="style.css" /> <script src="main.js"></script> </head> <body> 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<State>) -> 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<SpectateState>, state: Arc<State>) { 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; +} |