aboutsummaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-10-19 00:38:09 +0200
committermetamuffin <metamuffin@disroot.org>2025-10-19 00:38:09 +0200
commit62d918e5feeaf5b3add982a5baaffb201a1f2ece (patch)
treeb14a0fa01f9df692592bf5d16543f43b6eb933d6 /server
parent6b156bea343a0fd9a043dcfe7113986855a89aab (diff)
downloadhurrycurry-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.rs10
-rw-r--r--server/bot/src/main.rs4
-rw-r--r--server/client-lib/src/lib.rs2
-rw-r--r--server/editor/src/main.rs4
-rw-r--r--server/protocol/src/lib.rs7
-rw-r--r--server/src/entity/book.rs6
-rw-r--r--server/src/entity/bot.rs4
-rw-r--r--server/src/entity/campaign.rs6
-rw-r--r--server/src/entity/mod.rs4
-rw-r--r--server/src/entity/tutorial.rs10
-rw-r--r--server/src/server.rs204
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,
},