diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-10-19 00:38:09 +0200 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-10-19 00:38:09 +0200 |
| commit | 62d918e5feeaf5b3add982a5baaffb201a1f2ece (patch) | |
| tree | b14a0fa01f9df692592bf5d16543f43b6eb933d6 /server | |
| parent | 6b156bea343a0fd9a043dcfe7113986855a89aab (diff) | |
| download | hurrycurry-62d918e5feeaf5b3add982a5baaffb201a1f2ece.tar hurrycurry-62d918e5feeaf5b3add982a5baaffb201a1f2ece.tar.bz2 hurrycurry-62d918e5feeaf5b3add982a5baaffb201a1f2ece.tar.zst | |
Implement interaction with other players through id instead of tile pos
Diffstat (limited to 'server')
| -rw-r--r-- | server/bot/src/algos/customer.rs | 10 | ||||
| -rw-r--r-- | server/bot/src/main.rs | 4 | ||||
| -rw-r--r-- | server/client-lib/src/lib.rs | 2 | ||||
| -rw-r--r-- | server/editor/src/main.rs | 4 | ||||
| -rw-r--r-- | server/protocol/src/lib.rs | 7 | ||||
| -rw-r--r-- | server/src/entity/book.rs | 6 | ||||
| -rw-r--r-- | server/src/entity/bot.rs | 4 | ||||
| -rw-r--r-- | server/src/entity/campaign.rs | 6 | ||||
| -rw-r--r-- | server/src/entity/mod.rs | 4 | ||||
| -rw-r--r-- | server/src/entity/tutorial.rs | 10 | ||||
| -rw-r--r-- | server/src/server.rs | 204 |
11 files changed, 134 insertions, 127 deletions
diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs index 010ef48a..bd757d9e 100644 --- a/server/bot/src/algos/customer.rs +++ b/server/bot/src/algos/customer.rs @@ -24,7 +24,7 @@ use crate::{ }; use hurrycurry_client_lib::Game; use hurrycurry_protocol::{ - DemandIndex, Hand, Message, PacketS, PlayerClass, PlayerID, Score, + DemandIndex, Hand, ItemLocation, Message, PacketS, PlayerClass, PlayerID, Score, glam::{IVec2, Vec2}, }; use log::debug; @@ -314,7 +314,7 @@ impl CustomerState { player: me, }, PacketS::Interact { - pos: Some(pos), + target: Some(ItemLocation::Tile(pos)), player: me, hand: Hand(0), }, @@ -324,7 +324,7 @@ impl CustomerState { ..Default::default() }), PacketS::Interact { - pos: None, + target: None, player: me, hand: Hand(0), }, @@ -393,12 +393,12 @@ impl CustomerState { extra: vec![ PacketS::Interact { player: me, - pos: Some(*table), + target: Some(ItemLocation::Tile(*table)), hand: Hand(0), }, PacketS::Interact { player: me, - pos: None, + target: None, hand: Hand(0), }, ], diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs index d2bd10c5..22dc2e3f 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::{BotAlgo, BotInput, algos::ALGO_CONSTRUCTORS}; use hurrycurry_client_lib::{Game, network::sync::Network}; -use hurrycurry_protocol::{Character, Hand, PacketC, PacketS, PlayerClass, PlayerID}; +use hurrycurry_protocol::{Character, Hand, ItemLocation, PacketC, PacketS, PlayerClass, PlayerID}; use log::warn; use std::{thread::sleep, time::Duration}; @@ -119,7 +119,7 @@ fn main() -> Result<()> { b.interacting = interact.is_some(); network.queue_out.push_back(PacketS::Interact { player: b.id, - pos: interact, + target: interact.map(ItemLocation::Tile), hand: Hand(0), }) } diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs index 515b2e38..f2c47ea0 100644 --- a/server/client-lib/src/lib.rs +++ b/server/client-lib/src/lib.rs @@ -56,7 +56,7 @@ pub struct Player { pub name: String, pub class: PlayerClass, pub character: Character, - pub interacting: Option<(IVec2, Hand)>, + pub interacting: Option<(ItemLocation, Hand)>, pub items: Vec<Option<Item>>, pub communicate_persist: Option<(Message, MessageTimeout)>, diff --git a/server/editor/src/main.rs b/server/editor/src/main.rs index dc9c6735..be0fcbc5 100644 --- a/server/editor/src/main.rs +++ b/server/editor/src/main.rs @@ -305,7 +305,7 @@ impl State { } PacketS::Interact { hand: Hand(1), - pos: Some(_), + target: Some(_), .. } => { self.tile.0 += 1; @@ -317,7 +317,7 @@ impl State { } PacketS::Interact { hand: Hand(0), - pos: Some(_), + target: Some(_), .. } => { let bpos = self.movement.position.floor().as_ivec2(); diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index 82476eab..b686fcee 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -121,8 +121,7 @@ pub enum PacketS { Interact { player: PlayerID, hand: Hand, - #[serde(deserialize_with = "deser_ivec2_opt", default)] - pos: Option<IVec2>, + target: Option<ItemLocation>, }, Communicate { player: PlayerID, @@ -382,10 +381,6 @@ fn deser_usize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<usize, D::E let x = f64::deserialize(deserializer)?; Ok(x.trunc() as usize) } -fn deser_ivec2_opt<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<IVec2>, D::Error> { - let x = Option::<Vec2>::deserialize(deserializer)?; - Ok(x.map(|v| v.as_ivec2())) -} fn deser_tile_index_map<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<BTreeMap<TileIndex, HashSet<ItemIndex>>, D::Error> { diff --git a/server/src/entity/book.rs b/server/src/entity/book.rs index 8daec972..e8456591 100644 --- a/server/src/entity/book.rs +++ b/server/src/entity/book.rs @@ -18,7 +18,7 @@ use super::{Entity, EntityContext}; use anyhow::Result; use hurrycurry_locale::TrError; -use hurrycurry_protocol::{Menu, PacketC, PlayerID, glam::IVec2}; +use hurrycurry_protocol::{ItemLocation, Menu, PacketC, PlayerID, glam::IVec2}; #[derive(Debug, Clone)] pub struct Book(pub IVec2); @@ -27,10 +27,10 @@ impl Entity for Book { fn interact( &mut self, c: EntityContext<'_>, - pos: Option<IVec2>, + pos: Option<ItemLocation>, _player: PlayerID, ) -> Result<bool, TrError> { - if pos == Some(self.0) { + if pos == Some(ItemLocation::Tile(self.0)) { if let Some(r) = c.replies { r.push(PacketC::Menu(Menu::Book(c.serverdata.book.clone()))); } diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs index 78b300b6..9627bb76 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::{Character, Hand, PacketS, PlayerClass, PlayerID}; +use hurrycurry_protocol::{Character, Hand, ItemLocation, PacketS, PlayerClass, PlayerID}; use log::debug; use std::any::Any; @@ -71,7 +71,7 @@ impl<T: BotAlgo + Any> Entity for BotDriver<T> { self.interacting = input.interact.is_some(); c.packet_in.push_back(PacketS::Interact { player: self.id, - pos: input.interact, + target: input.interact.map(ItemLocation::Tile), hand: Hand(0), }) } diff --git a/server/src/entity/campaign.rs b/server/src/entity/campaign.rs index 33baf631..ddbdc3bc 100644 --- a/server/src/entity/campaign.rs +++ b/server/src/entity/campaign.rs @@ -21,7 +21,7 @@ use anyhow::Result; use hurrycurry_data::entities::GateCondition; use hurrycurry_locale::{TrError, trm}; use hurrycurry_protocol::{ - Message, PacketC, PlayerID, TileIndex, + ItemLocation, Message, PacketC, PlayerID, TileIndex, glam::{IVec2, Vec2}, }; @@ -70,10 +70,10 @@ impl Entity for Gate { fn interact( &mut self, c: EntityContext<'_>, - pos: Option<IVec2>, + pos: Option<ItemLocation>, _player: PlayerID, ) -> Result<bool, TrError> { - if !self.unlocked && pos == Some(self.pos) { + if !self.unlocked && pos == Some(ItemLocation::Tile(self.pos)) { c.packet_out.push_back(PacketC::ServerMessage { message: trm!( "s.campaign.unlock_condition", diff --git a/server/src/entity/mod.rs b/server/src/entity/mod.rs index 7c38e532..4bca9dc8 100644 --- a/server/src/entity/mod.rs +++ b/server/src/entity/mod.rs @@ -41,7 +41,7 @@ use environment_effect::{EnvironmentController, EnvironmentEffectController}; use hurrycurry_client_lib::Game; use hurrycurry_data::{Serverdata, entities::EntityDecl}; use hurrycurry_locale::TrError; -use hurrycurry_protocol::{Character, PacketC, PacketS, PlayerID, glam::IVec2}; +use hurrycurry_protocol::{Character, ItemLocation, PacketC, PacketS, PlayerID}; use item_portal::ItemPortal; use player_portal::PlayerPortal; use std::{ @@ -77,7 +77,7 @@ pub trait Entity: Any { fn interact( &mut self, _c: EntityContext<'_>, - _pos: Option<IVec2>, + _target: Option<ItemLocation>, _player: PlayerID, ) -> Result<bool, TrError> { Ok(false) diff --git a/server/src/entity/tutorial.rs b/server/src/entity/tutorial.rs index 69086165..8cc896ac 100644 --- a/server/src/entity/tutorial.rs +++ b/server/src/entity/tutorial.rs @@ -17,7 +17,7 @@ */ use super::{Entity, EntityContext}; use anyhow::Result; -use hurrycurry_locale::{TrError, trm}; +use hurrycurry_locale::trm; use hurrycurry_protocol::{ ItemIndex, Message, PacketC, PlayerID, Recipe, RecipeIndex, TileIndex, glam::IVec2, }; @@ -121,14 +121,6 @@ impl Entity for Tutorial { Ok(()) } - fn interact( - &mut self, - _c: EntityContext<'_>, - _pos: Option<IVec2>, - _player: PlayerID, - ) -> Result<bool, TrError> { - Ok(false) - } } struct StepContext<'a> { diff --git a/server/src/server.rs b/server/src/server.rs index 8675638b..954d9a2c 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -515,7 +515,11 @@ impl Server { } } } - PacketS::Interact { pos, player, hand } => { + PacketS::Interact { + target, + player, + hand, + } => { for e in &mut self.entities { if e.interact( EntityContext { @@ -529,7 +533,7 @@ impl Server { replies: Some(replies), dt: 0., }, - pos, + target, player, )? { return Ok(()); @@ -543,105 +547,113 @@ impl Server { .get_mut(&pid) .ok_or(tre!("s.error.no_player"))?; - let pos = pos.map(|p| (p, hand)); + let loc = target.map(|p| (p, hand)); - let ((pos, hand), edge) = match (pos, player.interacting) { + let ((loc, hand), edge) = match (loc, player.interacting) { (None, None) => return Ok(()), // this is silent because of auto release - (None, Some(pos)) => (pos, false), - (Some(pos), None) => (pos, true), + (None, Some(t)) => (t, false), + (Some(t), None) => (t, true), (Some(_), Some(_)) => return Err(tre!("s.error.already_interacting")), }; - let entpos = pos.as_vec2() + Vec2::splat(0.5); - if edge && entpos.distance(player.movement.position) > 2. { - return Err(tre!("s.error.interacting_too_far")); - } + let pos = match loc { + ItemLocation::Tile(pos) => pos.as_vec2() + Vec2::splat(0.5), + ItemLocation::Player(p, _) => { + self.game + .players + .get(&p) + .ok_or_else(|| tre!("s.error.no_player"))? + .movement + .position + } + }; - let tile = self + let player = self .game - .tiles - .get_mut(&pos) - .ok_or(tre!("s.error.no_tile"))?; + .players + .get_mut(&pid) + .ok_or(tre!("s.error.no_player"))?; + + if edge && pos.distance(player.movement.position) > 2. { + return Err(tre!("s.error.interacting_too_far")); + } // No going back from here on - player.interacting = if edge { Some((pos, hand)) } else { None }; + player.interacting = if edge { Some((loc, hand)) } else { None }; - // Dont try interacting with player it tile is interactable - let other_pid = if self - .game - .data - .tile_placeable_items - .get(&tile.kind) - // TODO check for hand item - .is_none_or(|p| p.is_empty()) - { - self.game - .players - .iter() - .find(|(id, p)| **id != pid && p.movement.position.distance(entpos) < 0.7) - .map(|(&id, _)| id) - } else { - None - }; + match loc { + ItemLocation::Tile(pos) => { + let player = self + .game + .players + .get_mut(&pid) + .ok_or(tre!("s.error.no_player"))?; - if let Some(base_pid) = other_pid { - if pid == base_pid { - return Err(tre!("s.error.self_interact")); - } - let [Some(other), Some(this)] = - self.game.players.get_disjoint_mut([&pid, &base_pid]) - else { - return Err(tre!("s.error.self_interact")); - }; + let hslot = player + .items + .get_mut(hand.0) + .ok_or(tre!("s.error.no_hand"))?; - if this.class == PlayerClass::Customer || other.class == PlayerClass::Customer { - return Err(tre!("s.error.customer_interact")); - } + let tile = self + .game + .tiles + .get_mut(&pos) + .ok_or(tre!("s.error.no_tile"))?; - let this_hslot = this.items.get_mut(hand.0).ok_or(tre!("s.error.no_hand"))?; - let other_hslot = other.items.get_mut(hand.0).ok_or(tre!("s.error.no_hand"))?; + interact( + &self.game.data, + edge, + Some(tile.kind), + Some(pid), + &mut tile.item, + ItemLocation::Tile(pos), + hslot, + ItemLocation::Player(pid, hand), + &mut self.game.score, + &mut self.score_changed, + false, + &mut self.packet_out, + ) + } + ItemLocation::Player(other_pid, other_hand) => { + if pid == other_pid { + return Err(tre!("s.error.self_interact")); + } + let [Some(other), Some(this)] = + self.game.players.get_disjoint_mut([&pid, &other_pid]) + else { + return Err(tre!("s.error.no_player")); + }; - interact( - &self.game.data, - edge, - None, - Some(pid), - this_hslot, - ItemLocation::Player(base_pid, hand), - other_hslot, - ItemLocation::Player(pid, hand), - &mut self.game.score, - &mut self.score_changed, - false, - &mut self.packet_out, - ) - } else { - let player = self - .game - .players - .get_mut(&pid) - .ok_or(tre!("s.error.no_player"))?; + if this.class == PlayerClass::Customer + || other.class == PlayerClass::Customer + { + return Err(tre!("s.error.customer_interact")); + } - let hslot = player - .items - .get_mut(hand.0) - .ok_or(tre!("s.error.no_hand"))?; + let this_hslot = + this.items.get_mut(hand.0).ok_or(tre!("s.error.no_hand"))?; + let other_hslot = other + .items + .get_mut(other_hand.0) + .ok_or(tre!("s.error.no_hand"))?; - interact( - &self.game.data, - edge, - Some(tile.kind), - Some(pid), - &mut tile.item, - ItemLocation::Tile(pos), - hslot, - ItemLocation::Player(pid, hand), - &mut self.game.score, - &mut self.score_changed, - false, - &mut self.packet_out, - ) + interact( + &self.game.data, + edge, + None, + Some(pid), + this_hslot, + ItemLocation::Player(other_pid, hand), + other_hslot, + ItemLocation::Player(pid, hand), + &mut self.game.score, + &mut self.score_changed, + false, + &mut self.packet_out, + ) + } } } PacketS::Communicate { @@ -781,20 +793,28 @@ impl Server { player.communicate_persist = None; } } - if let Some((pos, hand)) = player.interacting - && let Some(tile) = self.game.tiles.get(&pos) - && let Some(item) = &tile.item - && let Some(involvement) = &item.active - && involvement.position >= 1. - { - players_auto_release.push((*pid, hand)); + if let Some((loc, hand)) = player.interacting { + match loc { + ItemLocation::Tile(pos) => { + if let Some(tile) = self.game.tiles.get(&pos) + && let Some(item) = &tile.item + && let Some(involvement) = &item.active + && involvement.position >= 1. + { + players_auto_release.push((*pid, hand)); + } + } + ItemLocation::Player(_pid, _hand) => { + // TODO + } + } } } for (player, hand) in players_auto_release.drain(..) { let _ = self.packet_in( None, PacketS::Interact { - pos: None, + target: None, player, hand, }, |