aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-06-04 19:37:46 +0200
committermetamuffin <metamuffin@disroot.org>2024-06-04 19:37:46 +0200
commit473dc29e540cb1ed332b6f2895f6f6efe2d60e65 (patch)
treeccd869dab5adece9f9f6a7190ee56fe5ad1c7b3d
parentf39f9840a8d14f35de0d38c9570ae27bacb20119 (diff)
downloadgpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar
gpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar.bz2
gpn-tron-rust-473dc29e540cb1ed332b6f2895f6f6efe2d60e65.tar.zst
spectator see names
-rw-r--r--Cargo.lock60
-rw-r--r--Cargo.toml5
-rw-r--r--config.toml3
-rw-r--r--src/bot/mod.rs49
-rw-r--r--src/config.rs3
-rw-r--r--src/main.rs2
-rw-r--r--src/spectate/index.html1
-rw-r--r--src/spectate/main.ts29
-rw-r--r--src/spectate/server.rs30
-rw-r--r--src/spectate/style.css4
10 files changed, 175 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 9cc3262..9225731 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 4713f3c..1c6fdd2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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;
+}