summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/bot/src/algos/customer.rs13
-rw-r--r--server/bot/src/algos/simple.rs13
-rw-r--r--server/bot/src/main.rs3
-rw-r--r--server/client-lib/src/lib.rs21
-rw-r--r--server/protocol/src/helpers.rs30
-rw-r--r--server/protocol/src/lib.rs10
-rw-r--r--server/src/entity/bot.rs3
-rw-r--r--server/src/entity/tutorial.rs4
-rw-r--r--server/src/server.rs127
9 files changed, 145 insertions, 79 deletions
diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs
index b243bd55..826ab534 100644
--- a/server/bot/src/algos/customer.rs
+++ b/server/bot/src/algos/customer.rs
@@ -22,7 +22,7 @@ use crate::{
use hurrycurry_client_lib::Game;
use hurrycurry_protocol::{
glam::{IVec2, Vec2},
- DemandIndex, Message, PacketS, PlayerClass, PlayerID, Score,
+ DemandIndex, Hand, Message, PacketS, PlayerClass, PlayerID, Score,
};
use log::info;
use rand::{random, seq::IndexedRandom, thread_rng};
@@ -313,6 +313,7 @@ impl CustomerState {
PacketS::Interact {
pos: Some(pos),
player: me,
+ hand: Hand::Left,
},
PacketS::ApplyScore(Score {
demands_completed: 1,
@@ -322,6 +323,7 @@ impl CustomerState {
PacketS::Interact {
pos: None,
player: me,
+ hand: Hand::Left,
},
],
..Default::default()
@@ -354,6 +356,7 @@ impl CustomerState {
extra: vec![PacketS::ReplaceHand {
player: me,
item: demand.output,
+ hand: Hand::Left,
}],
..Default::default()
};
@@ -369,7 +372,11 @@ impl CustomerState {
cooldown,
} => {
*cooldown -= dt;
- if game.players.get(&me).is_some_and(|pl| pl.item.is_none()) {
+ if game
+ .players
+ .get(&me)
+ .is_some_and(|pl| pl.items[Hand::Left.index()].is_none())
+ {
if let Some(path) = find_path(&game.walkable, pos.as_ivec2(), *origin) {
*self = CustomerState::Exiting { path };
}
@@ -383,10 +390,12 @@ impl CustomerState {
PacketS::Interact {
player: me,
pos: Some(*table),
+ hand: Hand::Left,
},
PacketS::Interact {
player: me,
pos: None,
+ hand: Hand::Left,
},
],
direction,
diff --git a/server/bot/src/algos/simple.rs b/server/bot/src/algos/simple.rs
index 14eb38c4..5a7e61a0 100644
--- a/server/bot/src/algos/simple.rs
+++ b/server/bot/src/algos/simple.rs
@@ -21,7 +21,7 @@ use crate::{
};
use hurrycurry_client_lib::Game;
use hurrycurry_protocol::{
- glam::IVec2, ItemIndex, Message, PlayerID, Recipe, RecipeIndex, TileIndex,
+ glam::IVec2, Hand, ItemIndex, Message, PlayerID, Recipe, RecipeIndex, TileIndex,
};
use log::{debug, warn};
@@ -106,16 +106,17 @@ impl State for Simple {
impl<S> Context<'_, S> {
pub fn is_hand_item(&self, item: ItemIndex) -> bool {
- self.game
- .players
- .get(&self.me)
- .is_some_and(|p| p.item.as_ref().is_some_and(|i| i.kind == item))
+ self.game.players.get(&self.me).is_some_and(|p| {
+ p.items[Hand::Left.index()]
+ .as_ref()
+ .is_some_and(|i| i.kind == item)
+ })
}
pub fn is_hand_occupied(&self) -> bool {
self.game
.players
.get(&self.me)
- .map(|p| p.item.is_some())
+ .map(|p| p.items[Hand::Left.index()].is_some())
.unwrap_or(false)
}
pub fn find_demand(&self) -> Option<(ItemIndex, IVec2)> {
diff --git a/server/bot/src/main.rs b/server/bot/src/main.rs
index 61ae1c1c..0ffbf4b6 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, PlayerClass, PlayerID};
+use hurrycurry_protocol::{Hand, PacketC, PacketS, PlayerClass, PlayerID};
use log::warn;
use std::{thread::sleep, time::Duration};
@@ -109,6 +109,7 @@ fn main() -> Result<()> {
network.queue_out.push_back(PacketS::Interact {
player: b.id,
pos: interact,
+ hand: Hand::Left,
})
}
network.queue_out.push_back(PacketS::Movement {
diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs
index 5d5e55d5..54c7cd6e 100644
--- a/server/client-lib/src/lib.rs
+++ b/server/client-lib/src/lib.rs
@@ -20,8 +20,7 @@ pub mod network;
pub mod spatial_index;
use hurrycurry_protocol::{
- glam::IVec2, movement::MovementBase, Gamedata, ItemIndex, ItemLocation, Message,
- MessageTimeout, PacketC, PlayerClass, PlayerID, RecipeIndex, Score, TileIndex,
+ glam::IVec2, movement::MovementBase, Gamedata, Hand, ItemIndex, ItemLocation, Message, MessageTimeout, PacketC, PlayerClass, PlayerID, RecipeIndex, Score, TileIndex
};
use spatial_index::SpatialIndex;
use std::{
@@ -54,8 +53,8 @@ pub struct Player {
pub name: String,
pub class: PlayerClass,
pub character: i32,
- pub interacting: Option<IVec2>,
- pub item: Option<Item>,
+ pub interacting: Option<(IVec2, Hand)>,
+ pub items: [Option<Item>; 2],
pub communicate_persist: Option<(Message, MessageTimeout)>,
pub movement: MovementBase,
@@ -95,7 +94,7 @@ impl Game {
character,
class,
interacting: None,
- item: None,
+ items: [const { None }; 2],
communicate_persist: None,
movement: MovementBase::new(position),
},
@@ -200,9 +199,11 @@ impl Game {
}
for player in self.players.values_mut() {
- if let Some(item) = &mut player.item {
- if let Some(active) = &mut item.active {
- active.position += active.speed;
+ for item in &mut player.items {
+ if let Some(item) = item {
+ if let Some(active) = &mut item.active {
+ active.position += active.speed;
+ }
}
}
}
@@ -226,7 +227,9 @@ impl Game {
pub fn get_item(&mut self, location: ItemLocation) -> &mut Option<Item> {
match location {
ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item,
- ItemLocation::Player(pid) => &mut self.players.get_mut(&pid).unwrap().item,
+ ItemLocation::Player(pid, hand) => {
+ &mut self.players.get_mut(&pid).unwrap().items[hand.index()]
+ }
}
}
}
diff --git a/server/protocol/src/helpers.rs b/server/protocol/src/helpers.rs
index 924d0886..21835101 100644
--- a/server/protocol/src/helpers.rs
+++ b/server/protocol/src/helpers.rs
@@ -1,7 +1,8 @@
use std::fmt::Display;
use crate::{
- DocumentElement, Gamedata, ItemIndex, ItemLocation, PlayerID, Recipe, RecipeIndex, TileIndex,
+ DocumentElement, Gamedata, Hand, ItemIndex, ItemLocation, PlayerID, Recipe, RecipeIndex,
+ TileIndex,
};
impl Gamedata {
@@ -98,7 +99,32 @@ impl Display for ItemLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ItemLocation::Tile(pos) => write!(f, "tile({pos})"),
- ItemLocation::Player(PlayerID(id)) => write!(f, "player({id})"),
+ ItemLocation::Player(PlayerID(id), hand) => write!(f, "player({id}_{hand})"),
+ }
+ }
+}
+
+impl Display for Hand {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(match self {
+ Hand::Left => "left",
+ Hand::Right => "right",
+ })
+ }
+}
+
+impl Hand {
+ pub fn index(&self) -> usize {
+ match self {
+ Hand::Left => 0,
+ Hand::Right => 1,
+ }
+ }
+ pub fn from_index(i: usize) -> Self {
+ match i {
+ 0 => Hand::Left,
+ 1 => Hand::Right,
+ _ => Hand::Left,
}
}
}
diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs
index 2ef07015..6ccd2367 100644
--- a/server/protocol/src/lib.rs
+++ b/server/protocol/src/lib.rs
@@ -71,6 +71,12 @@ pub struct RecipeIndex(pub usize);
#[serde(transparent)]
pub struct DemandIndex(pub usize);
+#[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, Hash)]
+pub enum Hand {
+ Left,
+ Right,
+}
+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
pub struct MapMetadata {
pub name: String,
@@ -124,6 +130,7 @@ pub enum PacketS {
},
Interact {
player: PlayerID,
+ hand: Hand,
#[bincode(with_serde)]
pos: Option<IVec2>,
},
@@ -144,6 +151,7 @@ pub enum PacketS {
/// For internal use only (customers)
ReplaceHand {
player: PlayerID,
+ hand: Hand,
item: Option<ItemIndex>,
},
#[serde(skip)]
@@ -344,7 +352,7 @@ pub enum Recipe {
#[serde(rename_all = "snake_case")]
pub enum ItemLocation {
Tile(#[bincode(with_serde)] IVec2),
- Player(PlayerID),
+ Player(PlayerID, Hand),
}
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs
index fe4d711f..368f8c9d 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, PlayerClass, PlayerID};
+use hurrycurry_protocol::{Hand, PacketS, PlayerClass, PlayerID};
use log::info;
use rand::random;
use std::any::Any;
@@ -72,6 +72,7 @@ impl<T: BotAlgo + Any> Entity for BotDriver<T> {
c.packet_in.push_back(PacketS::Interact {
player: self.id,
pos: input.interact,
+ hand: Hand::Left,
})
}
c.packet_in.push_back(PacketS::Movement {
diff --git a/server/src/entity/tutorial.rs b/server/src/entity/tutorial.rs
index 44244862..33c0e507 100644
--- a/server/src/entity/tutorial.rs
+++ b/server/src/entity/tutorial.rs
@@ -144,7 +144,7 @@ impl StepContext<'_> {
.game
.players
.get(&self.player)
- .is_some_and(|p| p.item.as_ref().is_some_and(|i| i.kind == item))
+ .is_some_and(|p| p.items.iter().flatten().any(|i| i.kind == item))
}
pub fn find_demand(&self, item: ItemIndex) -> Option<IVec2> {
self.ent
@@ -228,7 +228,7 @@ impl StepContext<'_> {
.game
.players
.get(&self.player)
- .is_some_and(|p| p.item.as_ref().is_some_and(|i| i.kind == item))
+ .is_some_and(|p| p.items.iter().flatten().any(|i| i.kind == item))
{
if let Some(pos) = self.find_demand(item) {
Err((Some(pos), trm!("s.tutorial.serve")))
diff --git a/server/src/server.rs b/server/src/server.rs
index 9928ac90..9b90d6b3 100644
--- a/server/src/server.rs
+++ b/server/src/server.rs
@@ -28,8 +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, PlayerClass, PlayerID, Score,
- TileIndex,
+ Gamedata, Hand, ItemLocation, Menu, MessageTimeout, PacketC, PacketS, PlayerClass, PlayerID,
+ Score, TileIndex,
};
use log::{info, warn};
use rand::random;
@@ -163,26 +163,29 @@ impl GameServerExt for Game {
character: player.character,
name: player.name.clone(),
});
- if let Some(item) = &player.item {
- out.push(PacketC::SetItem {
- location: ItemLocation::Player(id),
- item: Some(item.kind),
- });
- if let Some(Involvement {
- player,
- position,
- speed,
- warn,
- ..
- }) = item.active
- {
- out.push(PacketC::SetProgress {
+ for (i, item) in player.items.iter().enumerate() {
+ let hand = Hand::from_index(i);
+ if let Some(item) = &item {
+ out.push(PacketC::SetItem {
+ location: ItemLocation::Player(id, hand),
+ item: Some(item.kind),
+ });
+ if let Some(Involvement {
player,
- item: ItemLocation::Player(id),
position,
speed,
warn,
- });
+ ..
+ }) = item.active
+ {
+ out.push(PacketC::SetProgress {
+ player,
+ item: ItemLocation::Player(id, hand),
+ position,
+ speed,
+ warn,
+ });
+ }
}
}
if let Some((message, timeout)) = &player.communicate_persist {
@@ -252,7 +255,7 @@ impl GameServerExt for Game {
self.players.insert(
id,
Player {
- item: None,
+ items: [const { None }; 2],
character,
class,
movement: MovementBase::new(position),
@@ -399,15 +402,18 @@ impl Server {
self.game.players_spatial_index.remove_entry(player);
- if let Some(item) = p.item {
- let pos = p.movement.position.floor().as_ivec2();
- if let Some(tile) = self.game.tiles.get_mut(&pos) {
- if tile.item.is_none() {
- self.packet_out.push_back(PacketC::SetItem {
- location: ItemLocation::Tile(pos),
- item: Some(item.kind),
- });
- tile.item = Some(item);
+ // TODO if holding two, one is destroyed
+ for item in p.items {
+ if let Some(item) = item {
+ let pos = p.movement.position.floor().as_ivec2();
+ if let Some(tile) = self.game.tiles.get_mut(&pos) {
+ if tile.item.is_none() {
+ self.packet_out.push_back(PacketC::SetItem {
+ location: ItemLocation::Tile(pos),
+ item: Some(item.kind),
+ });
+ tile.item = Some(item);
+ }
}
}
}
@@ -445,7 +451,7 @@ impl Server {
}
}
}
- PacketS::Interact { pos, player } => {
+ PacketS::Interact { pos, player, hand } => {
for e in &mut self.entities {
if e.interact(
EntityContext {
@@ -473,7 +479,9 @@ impl Server {
.get_mut(&pid)
.ok_or(tre!("s.error.no_player"))?;
- let (pos, edge) = match (pos, player.interacting) {
+ let pos = pos.map(|p| (p, hand));
+
+ let ((pos, hand), edge) = match (pos, player.interacting) {
(None, None) => return Ok(()), // this is silent because of auto release
(None, Some(pos)) => (pos, false),
(Some(pos), None) => (pos, true),
@@ -493,7 +501,7 @@ impl Server {
// No going back from here on
- player.interacting = if edge { Some(pos) } else { None };
+ player.interacting = if edge { Some((pos, hand)) } else { None };
let other_pid = if !self.game.data.is_tile_interactable(tile.kind) {
self.game
@@ -524,10 +532,10 @@ impl Server {
edge,
None,
Some(pid),
- &mut this.item,
- ItemLocation::Player(base_pid),
- &mut other.item,
- ItemLocation::Player(pid),
+ &mut this.items[hand.index()],
+ ItemLocation::Player(base_pid, hand),
+ &mut other.items[hand.index()],
+ ItemLocation::Player(pid, hand),
&mut self.game.score,
&mut self.score_changed,
false,
@@ -547,8 +555,8 @@ impl Server {
Some(pid),
&mut tile.item,
ItemLocation::Tile(pos),
- &mut player.item,
- ItemLocation::Player(pid),
+ &mut player.items[hand.index()],
+ ItemLocation::Player(pid, hand),
&mut self.game.score,
&mut self.score_changed,
false,
@@ -588,14 +596,14 @@ impl Server {
timeout,
});
}
- PacketS::ReplaceHand { item, player } => {
+ PacketS::ReplaceHand { item, player, hand } => {
let pdata = self.game.players.get_mut(&player).ok_or(tre!(""))?;
- pdata.item = item.map(|i| Item {
+ pdata.items[hand.index()] = item.map(|i| Item {
kind: i,
active: None,
});
self.packet_out.push_back(PacketC::SetItem {
- location: ItemLocation::Player(player),
+ location: ItemLocation::Player(player, hand),
item,
})
}
@@ -661,17 +669,19 @@ impl Server {
rot: player.movement.rotation,
});
- tick_slot(
- dt,
- &self.game.data,
- &self.gamedata_index,
- None,
- &mut player.item,
- ItemLocation::Player(pid),
- &mut self.game.score,
- &mut self.score_changed,
- &mut self.packet_out,
- );
+ for (i, item) in player.items.iter_mut().enumerate() {
+ tick_slot(
+ dt,
+ &self.game.data,
+ &self.gamedata_index,
+ None,
+ item,
+ ItemLocation::Player(pid, Hand::from_index(i)),
+ &mut self.game.score,
+ &mut self.score_changed,
+ &mut self.packet_out,
+ );
+ }
}
let mut players_auto_release = Vec::new();
@@ -682,20 +692,27 @@ impl Server {
player.communicate_persist = None;
}
}
- if let Some(pos) = player.interacting {
+ if let Some((pos, hand)) = player.interacting {
if let Some(tile) = self.game.tiles.get(&pos) {
if let Some(item) = &tile.item {
if let Some(involvement) = &item.active {
if involvement.position >= 1. {
- players_auto_release.push(*pid);
+ players_auto_release.push((*pid, hand));
}
}
}
}
}
}
- for player in players_auto_release.drain(..) {
- let _ = self.packet_in(PacketS::Interact { pos: None, player }, &mut vec![]);
+ for (player, hand) in players_auto_release.drain(..) {
+ let _ = self.packet_in(
+ PacketS::Interact {
+ pos: None,
+ player,
+ hand,
+ },
+ &mut vec![],
+ );
}
let mut load_map = None;