diff options
author | metamuffin <metamuffin@disroot.org> | 2024-09-25 15:30:09 +0200 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-09-25 15:55:00 +0200 |
commit | 9587d6b4d4389f6108e2be0ff5c0f4a495ff842d (patch) | |
tree | 3cc2ea9a93de6dd39acd5396fddfbadafef471cf | |
parent | 64564a25db65d7a578fee537a0cf91db1a7dbc60 (diff) | |
download | hurrycurry-9587d6b4d4389f6108e2be0ff5c0f4a495ff842d.tar hurrycurry-9587d6b4d4389f6108e2be0ff5c0f4a495ff842d.tar.bz2 hurrycurry-9587d6b4d4389f6108e2be0ff5c0f4a495ff842d.tar.zst |
player class decoupled from character id
-rw-r--r-- | pixel-client/src/game.rs | 15 | ||||
-rw-r--r-- | server/bot/src/algos/customer.rs | 12 | ||||
-rw-r--r-- | server/bot/src/algos/frank.rs | 4 | ||||
-rw-r--r-- | server/bot/src/main.rs | 5 | ||||
-rw-r--r-- | server/client-lib/src/lib.rs | 5 | ||||
-rw-r--r-- | server/protocol/src/lib.rs | 20 | ||||
-rw-r--r-- | server/registry/src/lobby.rs | 3 | ||||
-rw-r--r-- | server/src/commands.rs | 3 | ||||
-rw-r--r-- | server/src/entity/bot.rs | 11 | ||||
-rw-r--r-- | server/src/entity/customers.rs | 4 | ||||
-rw-r--r-- | server/src/main.rs | 3 | ||||
-rw-r--r-- | server/src/server.rs | 41 | ||||
-rw-r--r-- | test-client/main.ts | 6 | ||||
-rw-r--r-- | test-client/protocol.ts | 6 | ||||
-rw-r--r-- | test-client/visual.ts | 21 |
15 files changed, 108 insertions, 51 deletions
diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs index ca5f773a..f9891ae6 100644 --- a/pixel-client/src/game.rs +++ b/pixel-client/src/game.rs @@ -30,8 +30,8 @@ use hurrycurry_client_lib::{network::sync::Network, spatial_index::SpatialIndex, use hurrycurry_protocol::{ glam::{IVec2, Vec2}, movement::MovementBase, - Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerID, - RecipeIndex, Score, TileIndex, + Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerClass, + PlayerID, RecipeIndex, Score, TileIndex, }; use log::{info, warn}; use sdl2::{ @@ -71,6 +71,7 @@ pub struct Player { message_persist: Option<(Message, MessageTimeout)>, _name: String, _character: i32, + _class: PlayerClass, interact_target_anim: Vec2, interact_target_anim_pressed: f32, } @@ -88,6 +89,7 @@ impl Game { network.queue_out.push_back(PacketS::Join { id: None, name: config.username.clone(), + class: PlayerClass::Chef, character: 0, }); @@ -276,6 +278,7 @@ impl Game { position, character, name, + class, } => { info!("add player {} {name:?}", id.0); self.players.insert( @@ -283,6 +286,7 @@ impl Game { Player { interact_target_anim: position, interact_target_anim_pressed: 0., + _class: class, _character: character, _name: name, message_persist: None, @@ -467,10 +471,9 @@ impl Item { impl Player { pub fn draw(&self, ctx: &mut Renderer, item_sprites: &[Sprite]) { ctx.draw_world( - if self._character >= 0 { - &ctx.misc_textures.chef - } else { - &ctx.misc_textures.customer + match self._class { + PlayerClass::Chef | PlayerClass::Bot => &ctx.misc_textures.chef, + PlayerClass::Customer => &ctx.misc_textures.customer, } .at(self.movement.position), ); diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs index e602addc..6a45e379 100644 --- a/server/bot/src/algos/customer.rs +++ b/server/bot/src/algos/customer.rs @@ -20,7 +20,9 @@ use crate::{ BotAlgo, BotInput, }; use hurrycurry_client_lib::Game; -use hurrycurry_protocol::{glam::IVec2, DemandIndex, Message, PacketS, PlayerID, Score}; +use hurrycurry_protocol::{ + glam::IVec2, DemandIndex, Message, PacketS, PlayerClass, PlayerID, Score, +}; use log::info; use rand::{random, seq::IndexedRandom, thread_rng}; @@ -124,7 +126,7 @@ impl BotAlgo for Customer { .players .iter() .find(|(id, p)| { - p.character < 0 + p.class == PlayerClass::Customer && **id != me && p.movement.position.distance(chair.as_vec2() + 0.5) < 1. }) @@ -186,7 +188,11 @@ impl BotAlgo for Customer { if !*pinned { let mut pin = false; game.players_spatial_index.query(pos, 3., |pid, _| { - if game.players.get(&pid).map_or(false, |p| p.character >= 0) { + if game + .players + .get(&pid) + .map_or(false, |p| p.class.is_cheflike()) + { pin = true } }); diff --git a/server/bot/src/algos/frank.rs b/server/bot/src/algos/frank.rs index 854c73bb..1e02e297 100644 --- a/server/bot/src/algos/frank.rs +++ b/server/bot/src/algos/frank.rs @@ -20,7 +20,7 @@ use crate::{ BotAlgo, BotInput, }; use hurrycurry_client_lib::Game; -use hurrycurry_protocol::{glam::Vec2, Message, PacketS, PlayerID}; +use hurrycurry_protocol::{glam::Vec2, Message, PacketS, PlayerClass, PlayerID}; use rand::{seq::IndexedRandom, thread_rng}; #[derive(Default)] @@ -116,7 +116,7 @@ fn find_chef(game: &Game, me: PlayerID) -> Option<PlayerID> { let chefs = game .players .iter() - .filter(|(i, p)| p.character >= 0 && **i != me) + .filter(|(i, p)| p.class == PlayerClass::Chef && **i != me) .map(|(i, _)| *i) .collect::<Vec<_>>(); chefs.choose(&mut thread_rng()).copied() diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs index 0e6aed36..61ae1c1c 100644 --- a/server/bot/src/main.rs +++ b/server/bot/src/main.rs @@ -19,7 +19,7 @@ use anyhow::Result; use clap::Parser; use hurrycurry_bot::{algos::ALGO_CONSTRUCTORS, BotAlgo, BotInput}; use hurrycurry_client_lib::{network::sync::Network, Game}; -use hurrycurry_protocol::{PacketC, PacketS, PlayerID}; +use hurrycurry_protocol::{PacketC, PacketS, PlayerClass, PlayerID}; use log::warn; use std::{thread::sleep, time::Duration}; @@ -29,7 +29,7 @@ struct Args { #[arg(short, long)] username: Option<String>, /// Bot character id - #[arg(short, long, default_value_t = 51)] + #[arg(short, long, default_value_t = 0)] character: i32, algo: String, /// Websocket address of the server @@ -57,6 +57,7 @@ fn main() -> Result<()> { network.queue_out.push_back(PacketS::Join { name: format!("{}-bot", args.username.clone().unwrap_or(args.algo.clone())), character: args.character, + class: PlayerClass::Bot, id: None, }); diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs index fc0f8ae6..2bd8fb09 100644 --- a/server/client-lib/src/lib.rs +++ b/server/client-lib/src/lib.rs @@ -21,7 +21,7 @@ pub mod spatial_index; use hurrycurry_protocol::{ glam::IVec2, movement::MovementBase, Gamedata, ItemIndex, ItemLocation, Message, - MessageTimeout, PacketC, PlayerID, RecipeIndex, Score, TileIndex, + MessageTimeout, PacketC, PlayerClass, PlayerID, RecipeIndex, Score, TileIndex, }; use spatial_index::SpatialIndex; use std::{ @@ -52,6 +52,7 @@ pub struct Tile { pub struct Player { pub name: String, + pub class: PlayerClass, pub character: i32, pub interacting: Option<IVec2>, pub item: Option<Item>, @@ -84,6 +85,7 @@ impl Game { id, position, character, + class, name, } => { self.players.insert( @@ -91,6 +93,7 @@ impl Game { Player { name, character, + class, interacting: None, item: None, communicate_persist: None, diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index b44a55fb..4c2ff3f4 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -95,6 +95,8 @@ pub enum PacketS { Join { name: String, character: i32, + #[serde(default = "chef_class")] + class: PlayerClass, #[serde(skip)] // TODO fix bincode can still set id id: Option<PlayerID>, // used entity bots that cant receive a response }, @@ -146,6 +148,23 @@ pub enum PacketS { }, } +fn chef_class() -> PlayerClass { + PlayerClass::Chef +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum PlayerClass { + Chef, + Bot, + Customer, +} +impl PlayerClass { + pub fn is_cheflike(&self) -> bool { + matches!(self, Self::Bot | Self::Chef) + } +} + #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum Message { @@ -173,6 +192,7 @@ pub enum PacketC { id: PlayerID, #[bincode(with_serde)] position: Vec2, + class: PlayerClass, character: i32, name: String, }, diff --git a/server/registry/src/lobby.rs b/server/registry/src/lobby.rs index 8b501c46..886443f5 100644 --- a/server/registry/src/lobby.rs +++ b/server/registry/src/lobby.rs @@ -4,7 +4,7 @@ use hurrycurry_protocol::{ glam::{ivec2, vec2, IVec2, Vec2}, movement::MovementBase, registry::Entry, - Gamedata, PacketC, PacketS, PlayerID, TileIndex, VERSION, + Gamedata, PacketC, PacketS, PlayerClass, PlayerID, TileIndex, VERSION, }; use log::{error, info, warn}; use rocket::futures::{SinkExt, StreamExt}; @@ -133,6 +133,7 @@ async fn handle_conn(sock: TcpStream, addr: SocketAddr, entries: &[Entry]) -> Re out.push(PacketC::AddPlayer { id: PlayerID(0), position: movement.position, + class: PlayerClass::Chef, character, name, }); diff --git a/server/src/commands.rs b/server/src/commands.rs index 9d34c28c..06659161 100644 --- a/server/src/commands.rs +++ b/server/src/commands.rs @@ -23,7 +23,7 @@ use crate::{ use anyhow::{anyhow, bail, Result}; use clap::{Parser, ValueEnum}; use hurrycurry_bot::algos::ALGO_CONSTRUCTORS; -use hurrycurry_protocol::{Menu, Message, PacketC, PlayerID}; +use hurrycurry_protocol::{Menu, Message, PacketC, PlayerClass, PlayerID}; use std::{fmt::Write, time::Duration}; #[derive(Parser)] @@ -218,6 +218,7 @@ impl Server { self.entities.push(Box::new(BotDriver::new( format!("{}-bot", name.unwrap_or((*aname).to_owned())), 51, + PlayerClass::Bot, algo, ))); } diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs index cd505c4f..fe4d711f 100644 --- a/server/src/entity/bot.rs +++ b/server/src/entity/bot.rs @@ -18,7 +18,7 @@ use super::{Entity, EntityContext}; use anyhow::Result; use hurrycurry_bot::{BotAlgo, DynBotAlgo}; -use hurrycurry_protocol::{PacketS, PlayerID}; +use hurrycurry_protocol::{PacketS, PlayerClass, PlayerID}; use log::info; use rand::random; use std::any::Any; @@ -27,19 +27,19 @@ pub type DynBotDriver = BotDriver<DynBotAlgo>; pub struct BotDriver<T> { algo: T, - join_data: Option<(String, i32)>, + join_data: Option<(String, i32, PlayerClass)>, id: PlayerID, interacting: bool, left: bool, } impl<T: BotAlgo> BotDriver<T> { - pub fn new(name: String, character: i32, algo: T) -> Self { + pub fn new(name: String, character: i32, class: PlayerClass, algo: T) -> Self { Self { algo, id: PlayerID(0), interacting: false, - join_data: Some((name, character)), + join_data: Some((name, character, class)), left: false, } } @@ -49,13 +49,14 @@ impl<T: BotAlgo + Any> Entity for BotDriver<T> { self.left } fn tick(&mut self, c: EntityContext<'_>) -> Result<()> { - if let Some((name, character)) = self.join_data.take() { + if let Some((name, character, class)) = self.join_data.take() { self.id = PlayerID(random()); // TODO bad code, can collide info!("spawn {:?} ({name:?}, {character})", self.id); c.packet_in.push_back(PacketS::Join { name, character, id: Some(self.id), + class, }) } diff --git a/server/src/entity/customers.rs b/server/src/entity/customers.rs index aaf6995f..388f7b26 100644 --- a/server/src/entity/customers.rs +++ b/server/src/entity/customers.rs @@ -18,6 +18,7 @@ use super::{bot::BotDriver, Entity, EntityContext}; use anyhow::Result; use hurrycurry_bot::algos::Customer; +use hurrycurry_protocol::PlayerClass; use rand::random; pub struct Customers { @@ -53,7 +54,8 @@ impl Entity for Customers { self.spawn_cooldown = 10. + random::<f32>() * 10.; let bot = BotDriver::new( "".to_string(), - -1 - (random::<u16>() as i32), + random::<u16>() as i32, + PlayerClass::Customer, Customer::default(), ); self.customers.push(bot) diff --git a/server/src/main.rs b/server/src/main.rs index b72a961b..23c14e60 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -300,7 +300,7 @@ async fn run(args: Args) -> anyhow::Result<()> { #[cfg(test)] mod test { - use hurrycurry_protocol::{PacketS, PlayerID}; + use hurrycurry_protocol::{PacketS, PlayerClass, PlayerID}; use hurrycurry_server::{data::DATA_DIR, server::Server, ConnectionID}; use std::future::Future; use tokio::sync::broadcast; @@ -357,6 +357,7 @@ mod test { PacketS::Join { name: format!("test {conn}"), character: 1, + class: PlayerClass::Chef, id: None, }, ) diff --git a/server/src/server.rs b/server/src/server.rs index 5d31bd58..d44a949b 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -28,7 +28,8 @@ use hurrycurry_client_lib::{Game, Involvement, Item, Player, Tile}; use hurrycurry_protocol::{ glam::{IVec2, Vec2}, movement::MovementBase, - Gamedata, ItemLocation, Menu, MessageTimeout, PacketC, PacketS, PlayerID, Score, TileIndex, + Gamedata, ItemLocation, Menu, MessageTimeout, PacketC, PacketS, PlayerClass, PlayerID, Score, + TileIndex, }; use log::{info, warn}; use rand::random; @@ -71,6 +72,7 @@ pub trait GameServerExt { id: PlayerID, name: String, character: i32, + class: PlayerClass, serverdata: &Serverdata, packet_out: Option<&mut VecDeque<PacketC>>, ); @@ -105,11 +107,12 @@ impl GameServerExt for Game { timer: Option<Duration>, packet_out: &mut VecDeque<PacketC>, ) { + // TODO cleanup let players = self .players .iter() - .filter(|(_, p)| p.character >= 0) - .map(|(id, p)| (*id, (p.name.to_owned(), p.character))) + .filter(|(_, p)| p.class == PlayerClass::Chef) + .map(|(id, p)| (*id, (p.name.to_owned(), p.character, p.class))) .collect::<HashMap<_, _>>(); self.unload(packet_out); @@ -137,8 +140,8 @@ impl GameServerExt for Game { self.walkable.insert(p); } } - for (id, (name, character)) in players { - self.join_player(id, name, character, serverdata, None); + for (id, (name, character, class)) in players { + self.join_player(id, name, character, class, serverdata, None); } packet_out.extend(self.prime_client()); @@ -155,6 +158,7 @@ impl GameServerExt for Game { for (&id, player) in &self.players { out.push(PacketC::AddPlayer { id, + class: player.class, position: player.movement.position, character: player.character, name: player.name.clone(), @@ -236,19 +240,20 @@ impl GameServerExt for Game { id: PlayerID, name: String, character: i32, + class: PlayerClass, serverdata: &Serverdata, packet_out: Option<&mut VecDeque<PacketC>>, ) { - let position = if character < 0 { - serverdata.customer_spawn - } else { - serverdata.chef_spawn + let position = match class { + PlayerClass::Customer => serverdata.customer_spawn, + PlayerClass::Bot | PlayerClass::Chef => serverdata.chef_spawn, } + (Vec2::new(random(), random()) - 0.5); self.players.insert( id, Player { item: None, character, + class, movement: MovementBase::new(position), communicate_persist: None, interacting: None, @@ -260,6 +265,7 @@ impl GameServerExt for Game { packet_out.push_back(PacketC::AddPlayer { id, name, + class, position, character, }); @@ -357,14 +363,21 @@ impl Server { name, character, id, + class, } => { let id = id.unwrap_or_else(|| { let id = self.player_id_counter; self.player_id_counter.0 += 1; id }); - self.game - .join_player(id, name, character, &self.data, Some(&mut self.packet_out)); + self.game.join_player( + id, + name, + character, + class, + &self.data, + Some(&mut self.packet_out), + ); replies.push(PacketC::Joined { id }) } PacketS::Leave { player } => { @@ -488,7 +501,7 @@ impl Server { .get_many_mut([&pid, &base_pid]) .ok_or(tre!("s.error.self_interact"))?; - if this.character < 0 || other.character < 0 { + if this.class == PlayerClass::Customer || other.class == PlayerClass::Customer { return Err(tre!("s.error.customer_interact")); } @@ -730,7 +743,7 @@ impl Server { self.game .players .values() - .filter(|m| m.character >= 0) + .filter(|m| m.class == PlayerClass::Chef) .map(|m| m.name.clone()) .collect(), self.game.score.clone(), @@ -748,7 +761,7 @@ impl Server { self.game .players .values() - .map(|p| if p.character >= 0 { 1 } else { 0 }) + .map(|p| if p.class == PlayerClass::Chef { 1 } else { 0 }) .sum() } } diff --git a/test-client/main.ts b/test-client/main.ts index 3568244e..c56f9db4 100644 --- a/test-client/main.ts +++ b/test-client/main.ts @@ -20,7 +20,7 @@ import { init_locale } from "./locale.ts"; import { MovementBase, collide_player_player, update_movement } from "./movement.ts"; import { particle_splash, tick_particles } from "./particles.ts"; -import { Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerID, Score, TileIndex } from "./protocol.ts"; +import { Gamedata, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PacketS, PlayerClass, PlayerID, Score, TileIndex } from "./protocol.ts"; import { V2, lerp_exp_v2_mut, normalize, lerp_exp } from "./util.ts"; import { draw_ingame, draw_wait } from "./visual.ts"; @@ -50,7 +50,7 @@ document.addEventListener("DOMContentLoaded", async () => { ws.onclose = () => console.log("close") ws.onopen = () => { console.log("open") - send({ type: "join", name: "test", character: Math.floor(Math.random() * 255) }) + send({ type: "join", name: "test", character: Math.floor(Math.random() * 255), class: "chef" }) } canvas = document.createElement("canvas"); @@ -85,6 +85,7 @@ export interface PlayerData extends MovementBase { name: string, item?: ItemData, direction: V2, + class: PlayerClass, character: number, anim_position: V2, message_persist?: MessageData, @@ -153,6 +154,7 @@ function packet(p: PacketC) { position: { x: p.position[0], y: p.position[1], }, anim_position: { x: p.position[0], y: p.position[1] }, character: p.character, + class: p.class, name: p.name, rot: 0, facing: { x: 0, y: 1 }, diff --git a/test-client/protocol.ts b/test-client/protocol.ts index 64d740c3..2dcde685 100644 --- a/test-client/protocol.ts +++ b/test-client/protocol.ts @@ -36,7 +36,7 @@ export interface Gamedata { } export type PacketS = - { type: "join", name: string, character: number } // Spawns a new character. The server replies with "joined". Dont send it to spectate. + { type: "join", name: string, character: number, class: PlayerClass } // Spawns a new character. The server replies with "joined". Dont send it to spectate. | { 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 @@ -48,7 +48,7 @@ export type PacketC = { type: "version", minor: number, major: number, supports_bincode?: boolean } // Sent once after connecting to ensure you client is compatible | { type: "joined", id: PlayerID } // Informs you about the id of the character you spawned | { type: "data", data: Gamedata } // Game data was changed - | { type: "add_player", id: PlayerID, name: string, position: Vec2, character: number } // Somebody else joined (or was already in the game) + | { type: "add_player", id: PlayerID, name: string, position: Vec2, character: number, class: PlayerClass } // Somebody else joined (or was already in the game) | { type: "remove_player", id: PlayerID } // Somebody left | { type: "movement", player: PlayerID, pos: Vec2, rot: number, boost: boolean, dir: Vec2 } // Update the movement of a players (your own position is included here) | { type: "movement_sync" } // Your movement is difference on the server, you should update your position from a `position` packet @@ -98,3 +98,5 @@ export type Message = export type ItemLocation = { player: PlayerID } | { tile: Vec2 } + +export type PlayerClass = "chef" | "bot" | "customer" diff --git a/test-client/visual.ts b/test-client/visual.ts index 784a36a3..c5f34c1c 100644 --- a/test-client/visual.ts +++ b/test-client/visual.ts @@ -20,7 +20,7 @@ import { ItemData, MessageData, MessageStyle, PlayerData, TileData, camera, came import { PLAYER_SIZE } from "./movement.ts"; import { draw_item_sprite, draw_tile_sprite, ItemName, TileName } from "./tiles.ts"; import { V2, ceil_v2, floor_v2 } from "./util.ts"; -import { Message } from "./protocol.ts"; +import { Message, PlayerClass } from "./protocol.ts"; import { draw_particles, particle_count } from "./particles.ts"; export function draw_wait(text: string) { @@ -145,7 +145,7 @@ function draw_player(player: PlayerData) { ctx.translate(player.anim_position.x, player.anim_position.y) ctx.rotate(-player.rot) if (player.boosting) ctx.scale(1.3, 1.3) - draw_character(player.character) + draw_character(player.class, player.character) ctx.restore() if (player.item) draw_item(player.item) } @@ -200,24 +200,25 @@ function draw_grid() { ctx.stroke() } -function draw_character(character: number) { +function draw_character(pclass: PlayerClass, character: number) { ctx.fillStyle = `hsl(${character}rad, 50%, 50%)` ctx.beginPath() ctx.arc(0, 0, PLAYER_SIZE, 0, Math.PI * 2) ctx.fill() - if (character >= 0) { + if (pclass != "customer") { ctx.fillStyle = `hsl(${character}rad, 80%, 10%)` ctx.beginPath() ctx.arc(0, -0.2, PLAYER_SIZE, 0, Math.PI * 2) ctx.fill() } - - ctx.fillStyle = `hsl(${character}rad, 80%, 70%)` - ctx.beginPath() - ctx.moveTo(-0.04, 0.25) - ctx.lineTo(0.04, 0.25) - ctx.lineTo(0, 0.4) + if (pclass != "bot") { + ctx.fillStyle = `hsl(${character}rad, 80%, 70%)` + ctx.beginPath() + ctx.moveTo(-0.04, 0.25) + ctx.lineTo(0.04, 0.25) + ctx.lineTo(0, 0.4) + } ctx.fill() } |