summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2024-08-15 21:17:23 +0200
committermetamuffin <metamuffin@disroot.org>2024-08-15 21:17:23 +0200
commit1cb35341481cb76feb5bb794a304d1c4e3c7b372 (patch)
treedcd65f95aaa2805c14f83125ceb1bf11b6bf47be
parenta868f49b41c30daca83de86f982ffed431d3e891 (diff)
downloadhurrycurry-1cb35341481cb76feb5bb794a304d1c4e3c7b372.tar
hurrycurry-1cb35341481cb76feb5bb794a304d1c4e3c7b372.tar.bz2
hurrycurry-1cb35341481cb76feb5bb794a304d1c4e3c7b372.tar.zst
message timeout replaces persist
-rw-r--r--pixel-client/src/game.rs19
-rw-r--r--server/bot/src/algos/customer.rs19
-rw-r--r--server/bot/src/algos/simple.rs2
-rw-r--r--server/bot/src/algos/test.rs2
-rw-r--r--server/client-lib/src/lib.rs18
-rw-r--r--server/protocol/src/lib.rs10
-rw-r--r--server/src/server.rs33
-rw-r--r--server/src/state.rs6
-rw-r--r--test-client/main.ts54
-rw-r--r--test-client/protocol.ts9
-rw-r--r--test-client/visual.ts10
11 files changed, 116 insertions, 66 deletions
diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs
index 318b9a02..59b30ad0 100644
--- a/pixel-client/src/game.rs
+++ b/pixel-client/src/game.rs
@@ -30,7 +30,8 @@ use hurrycurry_client_lib::{network::sync::Network, spatial_index::SpatialIndex}
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
movement::MovementBase,
- Gamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, Score, TileIndex,
+ Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerID, Score,
+ TileIndex,
};
use log::{info, warn};
use sdl2::{
@@ -67,7 +68,7 @@ pub struct Tile {
pub struct Player {
movement: MovementBase,
item: Option<Item>,
- message_persist: Option<Message>,
+ message_persist: Option<(Message, MessageTimeout)>,
_name: String,
_character: i32,
interact_target_anim: Vec2,
@@ -183,6 +184,12 @@ impl Game {
for (&pid, player) in &mut self.players {
player.movement.update(&self.walkable, dt);
+ if let Some((_, timeout)) = &mut player.message_persist {
+ timeout.remaining -= dt;
+ if timeout.remaining < 0. {
+ player.message_persist = None;
+ }
+ }
self.players_spatial_index
.update_entry(pid, player.movement.position);
}
@@ -352,11 +359,11 @@ impl Game {
PacketC::Communicate {
player,
message,
- persist,
+ timeout,
} => {
- if persist {
+ if let Some(timeout) = timeout {
if let Some(player) = self.players.get_mut(&player) {
- player.message_persist = message;
+ player.message_persist = message.map(|m| (m, timeout));
}
}
}
@@ -458,7 +465,7 @@ impl Player {
}
.at(self.movement.position),
);
- if let Some(message) = &self.message_persist {
+ if let Some((message, _timeout)) = &self.message_persist {
match message {
Message::Text(_) => (), // TODO
Message::Item(item) => {
diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs
index 9c0ce210..2e0a45b4 100644
--- a/server/bot/src/algos/customer.rs
+++ b/server/bot/src/algos/customer.rs
@@ -91,16 +91,17 @@ impl BotAlgo for Customer {
if path.is_done() {
let demand = DemandIndex(random::<u32>() as usize % game.data.demands.len());
info!("{me:?} -> waiting");
+ let timeout = 90. + random::<f32>() * 60.;
*self = Customer::Waiting {
chair: *chair,
- timeout: 90. + random::<f32>() * 60.,
+ timeout,
demand,
origin: *origin,
};
BotInput {
extra: vec![PacketS::Communicate {
message: Some(Message::Item(game.data.demands[demand.0].input)),
- persist: true,
+ timeout: Some(timeout),
player: me,
}],
..Default::default()
@@ -137,13 +138,8 @@ impl BotAlgo for Customer {
..Default::default()
}),
PacketS::Communicate {
- message: None,
- persist: true,
- player: me,
- },
- PacketS::Communicate {
message: Some(Message::Effect("angry".to_string())),
- persist: false,
+ timeout: None,
player: me,
},
],
@@ -183,13 +179,8 @@ impl BotAlgo for Customer {
BotInput {
extra: vec![
PacketS::Communicate {
- persist: true,
- message: None,
- player: me,
- },
- PacketS::Communicate {
message: Some(Message::Effect("satisfied".to_string())),
- persist: false,
+ timeout: None,
player: me,
},
PacketS::Interact {
diff --git a/server/bot/src/algos/simple.rs b/server/bot/src/algos/simple.rs
index 1be2cddc..27493d74 100644
--- a/server/bot/src/algos/simple.rs
+++ b/server/bot/src/algos/simple.rs
@@ -123,7 +123,7 @@ impl<S> Context<'_, S> {
.players
.iter()
.find_map(|(_, pl)| match &pl.communicate_persist {
- Some(Message::Item(item)) => {
+ Some((Message::Item(item), _)) => {
let pos = pl.movement.position.as_ivec2();
[IVec2::X, IVec2::Y, -IVec2::X, -IVec2::Y]
.into_iter()
diff --git a/server/bot/src/algos/test.rs b/server/bot/src/algos/test.rs
index a47befa9..73368de2 100644
--- a/server/bot/src/algos/test.rs
+++ b/server/bot/src/algos/test.rs
@@ -59,7 +59,7 @@ fn find_demand(game: &Game) -> Option<(ItemIndex, IVec2)> {
game.players
.iter()
.find_map(|(_, pl)| match &pl.communicate_persist {
- Some(Message::Item(item)) => {
+ Some((Message::Item(item), _)) => {
let pos = pl.movement.position.as_ivec2();
let t = pos;
Some((*item, t))
diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs
index b04f46f7..38f1070e 100644
--- a/server/client-lib/src/lib.rs
+++ b/server/client-lib/src/lib.rs
@@ -20,8 +20,8 @@ pub mod network;
pub mod spatial_index;
use hurrycurry_protocol::{
- glam::IVec2, movement::MovementBase, Gamedata, ItemIndex, ItemLocation, Message, PacketC,
- PlayerID, RecipeIndex, Score, TileIndex,
+ glam::IVec2, movement::MovementBase, Gamedata, ItemIndex, ItemLocation, Message,
+ MessageTimeout, PacketC, PlayerID, RecipeIndex, Score, TileIndex,
};
use spatial_index::SpatialIndex;
use std::{
@@ -54,7 +54,7 @@ pub struct Player {
pub character: i32,
pub interacting: Option<IVec2>,
pub item: Option<Item>,
- pub communicate_persist: Option<Message>,
+ pub communicate_persist: Option<(Message, MessageTimeout)>,
pub movement: MovementBase,
}
@@ -168,11 +168,11 @@ impl Game {
PacketC::Communicate {
player,
message,
- persist,
+ timeout,
} => {
- if persist {
+ if let Some(timeout) = &timeout {
if let Some(player) = self.players.get_mut(&player) {
- player.communicate_persist = message;
+ player.communicate_persist = message.to_owned().map(|m| (m, *timeout));
}
}
}
@@ -195,6 +195,12 @@ impl Game {
for (&pid, player) in &mut self.players {
player.movement.update(&self.walkable, dt);
+ if let Some((_, timeout)) = &mut player.communicate_persist {
+ timeout.remaining -= dt;
+ if timeout.remaining < 0. {
+ player.communicate_persist = None;
+ }
+ }
self.players_spatial_index
.update_entry(pid, player.movement.position);
}
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 06cc9552..ee9fc0a3 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -116,7 +116,7 @@ pub enum PacketS {
Communicate {
player: PlayerID,
message: Option<Message>,
- persist: bool,
+ timeout: Option<f32>,
},
#[serde(skip)]
@@ -199,7 +199,7 @@ pub enum PacketC {
Communicate {
player: PlayerID,
message: Option<Message>,
- persist: bool,
+ timeout: Option<MessageTimeout>,
},
ServerMessage {
text: String,
@@ -231,6 +231,12 @@ pub enum Menu {
Score(Score),
}
+#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode)]
+pub struct MessageTimeout {
+ pub remaining: f32,
+ pub initial: f32,
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, Default)]
pub struct Score {
pub time_remaining: f64,
diff --git a/server/src/server.rs b/server/src/server.rs
index 41931ef7..2f93246d 100644
--- a/server/src/server.rs
+++ b/server/src/server.rs
@@ -25,7 +25,7 @@ use hurrycurry_client_lib::{Game, Item, Player, Tile};
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
movement::MovementBase,
- Gamedata, ItemLocation, Menu, PacketC, PacketS, PlayerID, Score, TileIndex,
+ Gamedata, ItemLocation, Menu, MessageTimeout, PacketC, PacketS, PlayerID, Score, TileIndex,
};
use log::{info, warn};
use std::{
@@ -177,11 +177,11 @@ impl GameServerExt for Game {
item: Some(item.kind),
})
}
- if let Some(c) = &player.communicate_persist {
+ if let Some((message, timeout)) = &player.communicate_persist {
out.push(PacketC::Communicate {
player: id,
- message: Some(c.to_owned()),
- persist: true,
+ message: Some(message.to_owned()),
+ timeout: Some(*timeout),
})
}
}
@@ -449,19 +449,30 @@ impl Server<'_> {
}
PacketS::Communicate {
message,
- persist,
+ timeout,
player,
} => {
info!("{player:?} message {message:?}");
- if persist {
+ if let Some(timeout) = timeout {
if let Some(player) = self.game.players.get_mut(&player) {
- player.communicate_persist = message.clone()
+ player.communicate_persist = message.clone().map(|m| {
+ (
+ m,
+ MessageTimeout {
+ initial: timeout,
+ remaining: timeout,
+ },
+ )
+ });
}
}
packet_out.push_back(PacketC::Communicate {
player,
message,
- persist,
+ timeout: timeout.map(|t| MessageTimeout {
+ initial: t,
+ remaining: t,
+ }),
})
}
PacketS::ReplaceHand { item, player } => {
@@ -595,6 +606,12 @@ impl Server<'_> {
let mut players_auto_release = Vec::new();
for (pid, player) in &mut self.game.players {
+ if let Some((_, timeout)) = &mut player.communicate_persist {
+ timeout.remaining -= dt;
+ if timeout.remaining < 0. {
+ player.communicate_persist = None;
+ }
+ }
if let Some(pos) = player.interacting {
if let Some(tile) = self.game.tiles.get(&pos) {
if let Some(item) = &tile.item {
diff --git a/server/src/state.rs b/server/src/state.rs
index 54beb3f7..f6304db5 100644
--- a/server/src/state.rs
+++ b/server/src/state.rs
@@ -148,7 +148,7 @@ impl State {
match &packet {
PacketS::Communicate {
message: Some(Message::Text(text)),
- persist: false,
+ timeout: None,
player,
} if let Some(command) = text.strip_prefix("/") => {
match self.handle_command_parse(*player, command).await {
@@ -288,7 +288,7 @@ impl State {
.send(PacketC::Communicate {
player,
message: Some(Message::Effect(name)),
- persist: false,
+ timeout: None,
})
.ok();
}
@@ -302,7 +302,7 @@ impl State {
.send(PacketC::Communicate {
player,
message: Some(Message::Item(item)),
- persist: false,
+ timeout: None,
})
.ok();
}
diff --git a/test-client/main.ts b/test-client/main.ts
index 1679ab42..2990c685 100644
--- a/test-client/main.ts
+++ b/test-client/main.ts
@@ -18,7 +18,7 @@
/// <reference lib="dom" />
import { MovementBase, collide_player_player, update_movement } from "./movement.ts";
-import { Gamedata, ItemIndex, ItemLocation, Message, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
+import { Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerID, TileIndex } from "./protocol.ts";
import { V2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts";
import { draw_ingame, draw_wait } from "./visual.ts";
@@ -79,8 +79,8 @@ export interface PlayerData extends MovementBase {
direction: V2,
character: number,
anim_position: V2,
+ message_persist?: MessageData,
message?: MessageData,
- message_clear?: number,
}
export interface TileData {
@@ -93,17 +93,17 @@ export interface MessageData {
inner: Message
anim_position: V2,
anim_size: number,
+ timeout: MessageTimeout,
}
export const players = new Map<PlayerID, PlayerData>()
export const tiles = new Map<string, TileData>()
export const items_removed = new Set<ItemData>()
-export let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0], tile_collide: [], tile_interact: [], maps: {} }
+export let data: Gamedata = { item_names: [], tile_names: [], spawn: [0, 0], tile_collide: [], tile_interact: [], maps: [] }
export let time_remaining: number | null = null
export let global_message: MessageData | undefined = undefined
-let global_message_clear: number | undefined = undefined
export let my_id: PlayerID = -1
export let points = 0
export let demands_completed = 0
@@ -206,10 +206,13 @@ function packet(p: PacketC) {
break;
case "communicate": {
const player = players.get(p.player)!
- if (player.message_clear) clearTimeout(player.message_clear)
- if (p.message) player.message = { inner: p.message, anim_size: 0., anim_position: player.anim_position }
- if (p.persist && !p.message) player.message = undefined
- if (!p.persist) player.message_clear = setTimeout(() => delete player.message, 3000)
+ if (p.message) {
+ const message = { inner: p.message, anim_size: 0., anim_position: player.anim_position, timeout: p.timeout ?? { initial: 5, remaining: 5 } };
+ if (p.timeout === undefined) player.message = message
+ else player.message_persist = message
+ } else if (p.timeout !== undefined) {
+ delete player.message_persist
+ }
break;
}
case "score":
@@ -219,15 +222,11 @@ function packet(p: PacketC) {
time_remaining = p.time_remaining ?? null
break;
case "error":
- if (global_message_clear) clearTimeout(global_message_clear)
- global_message = { inner: { text: p.message }, anim_size: 0., anim_position: { x: 0, y: 0 } }
- global_message_clear = setTimeout(() => global_message = undefined, 4000)
+ global_message = { inner: { text: p.message }, anim_size: 0., anim_position: { x: 0, y: 0 }, timeout: { initial: 5, remaining: 5 } }
console.warn(p.message)
break;
case "server_message":
- if (global_message_clear) clearTimeout(global_message_clear)
- global_message = { inner: { text: p.text }, anim_size: 0., anim_position: { x: 0, y: 0 } }
- global_message_clear = setTimeout(() => global_message = undefined, 4000)
+ global_message = { inner: { text: p.text }, anim_size: 0., anim_position: { x: 0, y: 0 }, timeout: { initial: 5, remaining: 5 } }
break;
case "set_ingame":
console.log(`ingame ${p.state}`);
@@ -257,12 +256,12 @@ function keyboard(ev: KeyboardEvent, down: boolean) {
if (HANDLED_KEYS.includes(ev.code)) ev.preventDefault()
if (!keys_down.has(KEY_INTERACT) && ev.code == KEY_INTERACT && down) set_interact(true)
if (keys_down.has(KEY_INTERACT) && ev.code == KEY_INTERACT && !down) set_interact(false)
- if (down && ev.code == "Numpad1") send({ player: my_id, type: "communicate", message: { text: "/start junior" }, persist: false })
- if (down && ev.code == "Numpad2") send({ player: my_id, type: "communicate", message: { text: "/start senior" }, persist: false })
- if (down && ev.code == "Numpad3") send({ player: my_id, type: "communicate", message: { text: "/start sophomore" }, persist: false })
- if (down && ev.code == "Numpad4") send({ player: my_id, type: "communicate", message: { text: "/start debug" }, persist: false })
- if (down && ev.code == "Numpad5") send({ player: my_id, type: "communicate", message: { text: "/start bus" }, persist: false })
- if (down && ev.code == "Numpad0") send({ player: my_id, type: "communicate", message: { text: "/end" }, persist: false })
+ if (down && ev.code == "Numpad1") send({ player: my_id, type: "communicate", message: { text: "/start junior" } })
+ if (down && ev.code == "Numpad2") send({ player: my_id, type: "communicate", message: { text: "/start senior" } })
+ if (down && ev.code == "Numpad3") send({ player: my_id, type: "communicate", message: { text: "/start sophomore" } })
+ if (down && ev.code == "Numpad4") send({ player: my_id, type: "communicate", message: { text: "/start debug" } })
+ if (down && ev.code == "Numpad5") send({ player: my_id, type: "communicate", message: { text: "/start bus" } })
+ if (down && ev.code == "Numpad0") send({ player: my_id, type: "communicate", message: { text: "/end" } })
if (down) keys_down.add(ev.code)
else keys_down.delete(ev.code)
}
@@ -275,7 +274,7 @@ function close_chat() {
}
function toggle_chat() {
if (chat) {
- if (chat.value.length) send({ player: my_id, type: "communicate", message: { text: chat.value }, persist: false })
+ if (chat.value.length) send({ player: my_id, type: "communicate", message: { text: chat.value } })
chat.remove()
canvas.focus()
chat = null;
@@ -342,7 +341,9 @@ function frame_update(dt: number) {
if (pid == my_id) player.anim_position.x = player.position.x, player.anim_position.y = player.position.y
else lerp_exp_v2_mut(player.anim_position, player.position, dt * 15)
if (player.item !== undefined && player.item !== null) update_item(player.item)
- if (player.message) player.message.anim_size = lerp_exp(player.message.anim_size, 1, dt * 3)
+ if (player.message && tick_message(player.message, dt)) delete player.message
+ if (player.message_persist && tick_message(player.message_persist, dt)) delete player.message_persist
+
}
for (const [_, tile] of tiles) {
if (tile.item !== undefined && tile.item !== null) update_item(tile.item)
@@ -359,6 +360,8 @@ function frame_update(dt: number) {
lerp_exp_v2_mut(camera, p.position, dt * 10.)
+ if (global_message && tick_message(global_message, dt)) global_message = undefined
+
const it = get_interact_target() ?? { x: 0, y: 0 };
const possible = data.tile_interact[tiles.get([it.x, it.y].toString())?.kind ?? 0] ?? false
lerp_exp_v2_mut(interact_target_anim, it, dt * 15.)
@@ -387,3 +390,10 @@ function draw() {
else throw new Error(`ws state invalid`);
requestAnimationFrame(draw)
}
+
+function tick_message(m: MessageData | undefined, dt: number): boolean {
+ if (!m) return true
+ m.anim_size = lerp_exp(m.anim_size, m.timeout.remaining > 0.3 ? 1 : 0, dt * 3)
+ m.timeout.remaining -= dt;
+ return m.timeout.remaining <= 0
+}
diff --git a/test-client/protocol.ts b/test-client/protocol.ts
index d5ce67ff..40532c08 100644
--- a/test-client/protocol.ts
+++ b/test-client/protocol.ts
@@ -40,7 +40,7 @@ export type PacketS =
| { type: "leave", player: PlayerID } // Despawns a character
| { type: "movement", player: PlayerID, pos: Vec2, dir: Vec2, boost: boolean }
| { type: "interact", player: PlayerID, pos?: Vec2 } // Interact with some tile. pos is a position when pressing and null when releasing interact button
- | { type: "communicate", player: PlayerID, message?: Message, persist: boolean } // Send a message
+ | { type: "communicate", player: PlayerID, message?: Message, timeout?: number } // Send a message
| { type: "replay_tick", dt: number } // Steps forward in replay.
export type PacketC =
@@ -55,7 +55,7 @@ export type PacketC =
| { type: "set_item", location: ItemLocation, item?: ItemIndex } // the item contained in a tile or player changed
| { type: "set_progress", item: ItemLocation, progress?: number, warn: boolean } // A tile is doing something. progress goes from 0 to 1, then null when finished
| { type: "update_map", tile: Vec2, kind: TileIndex | null, neighbors: [TileIndex | null] } // A map tile was changed
- | { type: "communicate", player: PlayerID, message?: Message, persist: boolean } // A player wants to communicate something, message is null when cleared
+ | { type: "communicate", player: PlayerID, message?: Message, timeout?: MessageTimeout } // A player wants to communicate something, message is null when cleared
| { type: "server_message", text: string } // Text message from the server
| { type: "score" } & Score // Supplies information for score OSD
| { type: "menu" } & Menu // Open a menu on the client-side
@@ -67,6 +67,11 @@ export type Menu =
{ menu: "book" }
| { menu: "score", data: Score }
+export interface MessageTimeout {
+ initial: number,
+ remaining: number
+}
+
export interface Score {
points: number,
demands_failed: number,
diff --git a/test-client/visual.ts b/test-client/visual.ts
index 07cfde67..59734234 100644
--- a/test-client/visual.ts
+++ b/test-client/visual.ts
@@ -66,8 +66,10 @@ export function draw_ingame() {
if (tile.item) draw_item(tile.item)
// Draw player messages
- for (const [_, player] of players)
+ for (const [_, player] of players) {
if (player.message) draw_message(player.message)
+ if (player.message_persist) draw_message(player.message_persist)
+ }
for (const [_, player] of players)
draw_player_nametag(player)
@@ -219,6 +221,12 @@ function draw_message(m: MessageData) {
ctx.closePath()
ctx.fill()
+ ctx.beginPath()
+ ctx.strokeStyle = "red"
+ ctx.lineWidth = 0.1
+ ctx.arc(0, -1, 0.45, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * (1 - m.timeout.remaining / m.timeout.initial))
+ ctx.stroke()
+
ctx.translate(0, -1)
draw_item_sprite(ctx, data.item_names[m.inner.item] as ItemName)
ctx.translate(0, 1)