From b0df9b7c27a3d6316969d7feff4d912c3abf99f6 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Mon, 23 Dec 2024 15:37:11 +0100 Subject: two-handed server --- server/bot/src/algos/customer.rs | 13 +++++++++++-- server/bot/src/algos/simple.rs | 13 +++++++------ server/bot/src/main.rs | 3 ++- 3 files changed, 20 insertions(+), 9 deletions(-) (limited to 'server/bot/src') 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 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 { -- cgit v1.2.3-70-g09d2 From 4083df5cfe76e42506c5356cf23d3dc9f3b6e6bf Mon Sep 17 00:00:00 2001 From: metamuffin Date: Wed, 25 Dec 2024 19:37:20 +0100 Subject: variable hand count --- client/game.gd | 14 +++++----- client/global.gd | 9 ++++--- client/multiplayer.gd | 3 ++- client/player/controllable_player.gd | 12 ++++----- client/player/player.gd | 31 +++++++++++----------- locale/en.ini | 1 + pixel-client/src/game.rs | 50 ++++++++++++++++++++++------------- server/bot/src/algos/customer.rs | 13 ++++----- server/bot/src/algos/simple.rs | 13 +++++---- server/bot/src/main.rs | 2 +- server/client-lib/src/lib.rs | 51 ++++++++++++++++++++++++------------ server/protocol/src/helpers.rs | 21 +-------------- server/protocol/src/lib.rs | 8 +++--- server/src/data/mod.rs | 1 + server/src/entity/bot.rs | 2 +- server/src/server.rs | 33 ++++++++++++++--------- 16 files changed, 144 insertions(+), 120 deletions(-) (limited to 'server/bot/src') diff --git a/client/game.gd b/client/game.gd index 9a6b8808..9502d2fc 100644 --- a/client/game.gd +++ b/client/game.gd @@ -144,13 +144,13 @@ func handle_packet(p): player_instance.position_ = last_position "move_item": if "player" in p.from and "player" in p.to: - players[p.from.player[0]].pass_to(players[p.to.player[0]], p.from.player[1], p.to.player[1]) + players[p.from.player[0]].pass_to(players[p.to.player[0]], int(p.from.player[1]), int(p.to.player[1])) elif "tile" in p.from and "player" in p.to: var t: Tile = map.get_tile_instance(p.from.tile) - players[p.to.player[0]].take_item(t, p.to.player[1]) + players[p.to.player[0]].take_item(t, int(p.to.player[1])) elif "player" in p.from and "tile" in p.to: var t: Tile = map.get_tile_instance(p.to.tile) - players[p.from.player[0]].put_item(t, p.from.player[1]) + players[p.from.player[0]].put_item(t, int(p.from.player[1])) elif "tile" in p.from and "tile" in p.to: var from_tile2: Tile = map.get_tile_instance(p.from.tile) var to_tile2: Tile = map.get_tile_instance(p.to.tile) @@ -160,13 +160,13 @@ func handle_packet(p): var t: Tile = map.get_tile_instance(p.item.tile) t.progress(p.position, p.speed, p.warn, players.get(p.player)) else: - players[p.item.player[0]].progress(p.position, p.speed, p.warn, p.item.player[1]) + players[p.item.player[0]].progress(p.position, p.speed, p.warn, int(p.item.player[1])) "clear_progress": if "tile" in p.item: var t: Tile = map.get_tile_instance(p.item.tile) t.finish() else: - players[p.item.player[0]].finish(p.item.player[1]) + players[p.item.player[0]].finish(int(p.item.player[1])) "set_item": var location: Dictionary = p["location"] if p.item != null: @@ -180,8 +180,8 @@ func handle_packet(p): else: var pl: Player = players[p.location.player[0]] var h = p.location.player[1] - var i = ItemFactory.produce(item_names[p.item], pl.hand_base[G.hand_to_index(h)]) - i.position = pl.hand_base[G.hand_to_index(h)].global_position + var i = ItemFactory.produce(item_names[p.item], pl.hand_base[h]) + i.position = pl.hand_base[h].global_position add_child(i) i.name = item_names[p.item] pl.set_item(i, h) diff --git a/client/global.gd b/client/global.gd index ce24f85d..93c73e13 100644 --- a/client/global.gd +++ b/client/global.gd @@ -269,7 +269,8 @@ func configure_viewport_aa(vp: Viewport, aa: String) -> void: vp.msaa_3d = Viewport.MSAA_4X vp.screen_space_aa = Viewport.SCREEN_SPACE_AA_DISABLED -static func hand_to_index(h): - match h: - "left": return 0 - "right": return 1 +static func index_to_hand(i): + match i: + 0: return "left" + 1: return "right" + _: return "unknown" diff --git a/client/multiplayer.gd b/client/multiplayer.gd index 14eaf482..11a5bd84 100644 --- a/client/multiplayer.gd +++ b/client/multiplayer.gd @@ -66,6 +66,7 @@ func fix_packet_types(val): if typeof(val[k]) == TYPE_ARRAY and val[k].size() == 2 and typeof(val[k][0]) == TYPE_FLOAT and typeof(val[k][1]) == TYPE_FLOAT: if k in ["tile"]: newval[k] = Vector2i(val[k][0], val[k][1]) elif k in ["pos", "position"]: newval[k] = Vector2(val[k][0], val[k][1]) + else: newval[k] = val[k] # TODO reenable when fixed # elif k in ["player", "id"] and typeof(val[k]) == TYPE_FLOAT: # newval[k] = int(val[k]) @@ -106,7 +107,7 @@ func send_movement(player, pos: Vector2, direction: Vector2, boost: bool): "boost": boost }) -func send_tile_interact(player, pos: Vector2i, edge: bool, hand: String): +func send_tile_interact(player, pos: Vector2i, edge: bool, hand: int): @warning_ignore("incompatible_ternary") send_packet({ "type": "interact", diff --git a/client/player/controllable_player.gd b/client/player/controllable_player.gd index d241bc2e..99625762 100644 --- a/client/player/controllable_player.gd +++ b/client/player/controllable_player.gd @@ -190,13 +190,13 @@ func _on_vibration_timeout(): Input.vibrate_handheld(100, vibration_strength) vibration_timer.start() -func put_item(tile: Tile, h): +func put_item(tile: Tile, h: int): super(tile, h) if Global.get_setting("gameplay.vibration"): Input.start_joy_vibration(0, 0.1, 0.0, 0.075) Input.vibrate_handheld(75, 0.1) -func take_item(tile: Tile, h): +func take_item(tile: Tile, h: int): super(tile, h) if Global.get_setting("gameplay.vibration"): Input.start_joy_vibration(0, 0.1, 0.0, 0.075) @@ -210,18 +210,18 @@ func interact(): # clear last interaction if target has moved since if last_interaction != null and not last_interaction == target: - game.mp.send_tile_interact(game.player_id, last_interaction, false, "left") + game.mp.send_tile_interact(game.player_id, last_interaction, false, 0) marker.set_interacting(false) last_interaction = null marker.set_interactive(game.get_tile_interactive(target)) marker_target = tile.item_base.global_position - for h in ["left", "right"]: - if Input.is_action_just_pressed("interact_"+h) and last_interaction == null: + for h in [0, 1]: + if Input.is_action_just_pressed("interact_"+G.index_to_hand(h)) and last_interaction == null: last_interaction = target game.mp.send_tile_interact(game.player_id, target, true, h) tile.interact() marker.set_interacting(true) - if Input.is_action_just_released("interact_"+h): + if Input.is_action_just_released("interact_"+G.index_to_hand(h)): last_interaction = null game.mp.send_tile_interact(game.player_id, target, false, h) marker.set_interacting(false) diff --git a/client/player/player.gd b/client/player/player.gd index 223d2c88..39b9fb3e 100644 --- a/client/player/player.gd +++ b/client/player/player.gd @@ -50,6 +50,7 @@ var current_item_message = null var _anim_angle: float = 0.0 var hand_base_position = [DEFAULT_HAND_BASE_POSITION_LEFT, DEFAULT_HAND_BASE_POSITION_RIGHT] +const DEFAULT_HAND_BASE_POSITION_BOTH: Vector3 = Vector3(0, .425, .4) const DEFAULT_HAND_BASE_POSITION_LEFT: Vector3 = Vector3(.3, .425, .4) const DEFAULT_HAND_BASE_POSITION_RIGHT: Vector3 = Vector3(-.3, .425, .4) @@ -100,42 +101,42 @@ func update_username_tag(state): tag.text = username tag.visible = state -func set_item(i: Item, h): - if hand[G.hand_to_index(h)] != null: hand[G.hand_to_index(h)].remove() +func set_item(i: Item, h: int): + if hand[h] != null: hand[h].remove() if i != null: @warning_ignore("static_called_on_instance") hand_base_position[0] = DEFAULT_HAND_BASE_POSITION_LEFT - Vector3(0.,i.height() * 0.5, 0.) @warning_ignore("static_called_on_instance") hand_base_position[1] = DEFAULT_HAND_BASE_POSITION_RIGHT - Vector3(0.,i.height() * 0.5, 0.) character.holding = i != null - hand[G.hand_to_index(h)] = i - if hand[G.hand_to_index(h)] != null: hand[G.hand_to_index(h)].owned_by = hand_base[G.hand_to_index(h)] + hand[h] = i + if hand[h] != null: hand[h].owned_by = hand_base[h] -func remove_item(h): - var i = hand[G.hand_to_index(h)] +func remove_item(h: int): + var i = hand[h] if i == null: push_error("holding nothing") - hand[G.hand_to_index(h)] = null + hand[h] = null character.holding = false return i -func progress(position__: float, speed: float, warn: bool, h): - if hand[G.hand_to_index(h)] != null: hand[G.hand_to_index(h)].progress(position__, speed, warn) +func progress(position__: float, speed: float, warn: bool, h: int): + if hand[h] != null: hand[h].progress(position__, speed, warn) -func finish(h): - if hand[G.hand_to_index(h)] != null: hand[G.hand_to_index(h)].finish() +func finish(h: int): + if hand[h] != null: hand[h].finish() -func take_item(tile: Tile, h): - if hand[G.hand_to_index(h)] != null: push_error("already holding an item") +func take_item(tile: Tile, h: int): + if hand[h] != null: push_error("already holding an item") var i = tile.take_item() i.take() set_item(i, h) -func put_item(tile: Tile, h): +func put_item(tile: Tile, h: int): var i = remove_item(h) i.put() tile.put_item(i) -func pass_to(player: Player, hfrom, hto): +func pass_to(player: Player, hfrom: int, hto: int): var i = remove_item(hfrom) i.player_owned_timer = 0 if player.hand != null: diff --git a/locale/en.ini b/locale/en.ini index c99b8e31..041e79bc 100644 --- a/locale/en.ini +++ b/locale/en.ini @@ -223,6 +223,7 @@ s.error.must_be_alone=You must be alone in this server to reload s.error.no_info=No information available. s.error.no_player=Player does not exist. s.error.no_tile=Tile does not exist. +s.error.no_hand=Hand does not exist. s.error.packet_not_supported=Packet not supported in this session. s.error.packet_sender_invalid=Packet sent to a player that is not owned by this connection. s.error.quoting_invalid=Command quoting invalid diff --git a/pixel-client/src/game.rs b/pixel-client/src/game.rs index 4dc43b72..cbcc62d5 100644 --- a/pixel-client/src/game.rs +++ b/pixel-client/src/game.rs @@ -156,13 +156,13 @@ impl Game { self.network.queue_out.push_back(PacketS::Interact { player: self.my_id, pos: Some(self.players[&self.my_id].movement.get_interact_target()), - hand: Hand::Left, + hand: Hand(0), }); } else { self.network.queue_out.push_back(PacketS::Interact { player: self.my_id, pos: None, - hand: Hand::Left, + hand: Hand(0), }); } self.interacting = interact; @@ -331,19 +331,23 @@ impl Game { } } PacketC::MoveItem { from, to } => { - let mut item = self.get_item(from).take(); + let mut item = self.get_item(from).unwrap().take(); if let Some(item) = &mut item { item.parent_position = self.get_location_position(to); } - *self.get_item(to) = item; + *self.get_item(to).unwrap() = item; } PacketC::SetItem { location, item } => { let position = self.get_location_position(location); let slot = match location { ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item, - ItemLocation::Player(pid, hand) => { - &mut self.players.get_mut(&pid).unwrap().items[hand.index()] - } + ItemLocation::Player(pid, hand) => self + .players + .get_mut(&pid) + .unwrap() + .items + .get_mut(hand.0) + .unwrap(), }; self.items_removed.extend(slot.take()); *slot = item.map(|kind| Item { @@ -354,7 +358,13 @@ impl Game { active: None, }) } - PacketC::ClearProgress { item } => self.get_item(item).as_mut().unwrap().active = None, + PacketC::ClearProgress { item } => { + if let Some(slot) = self.get_item(item) { + if let Some(item) = slot { + item.active = None; + } + } + } PacketC::SetProgress { item, position, @@ -362,13 +372,17 @@ impl Game { player, warn, } => { - self.get_item(item).as_mut().unwrap().active = Some(Involvement { - position, - speed, - player, - warn, - recipe: RecipeIndex(0), - }); + if let Some(slot) = self.get_item(item) { + if let Some(item) = slot { + item.active = Some(Involvement { + position, + speed, + player, + warn, + recipe: RecipeIndex(0), + }); + } + } } PacketC::ServerMessage { .. } => { // TODO @@ -392,11 +406,11 @@ impl Game { } } - pub fn get_item(&mut self, location: ItemLocation) -> &mut Option { + pub fn get_item(&mut self, location: ItemLocation) -> Option<&mut Option> { match location { - ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item, + ItemLocation::Tile(pos) => Some(&mut self.tiles.get_mut(&pos)?.item), ItemLocation::Player(pid, hand) => { - &mut self.players.get_mut(&pid).unwrap().items[hand.index()] + Some(self.players.get_mut(&pid)?.items.get_mut(hand.0)?) } } } diff --git a/server/bot/src/algos/customer.rs b/server/bot/src/algos/customer.rs index 826ab534..b0ece9dd 100644 --- a/server/bot/src/algos/customer.rs +++ b/server/bot/src/algos/customer.rs @@ -313,7 +313,7 @@ impl CustomerState { PacketS::Interact { pos: Some(pos), player: me, - hand: Hand::Left, + hand: Hand(0), }, PacketS::ApplyScore(Score { demands_completed: 1, @@ -323,7 +323,7 @@ impl CustomerState { PacketS::Interact { pos: None, player: me, - hand: Hand::Left, + hand: Hand(0), }, ], ..Default::default() @@ -356,7 +356,7 @@ impl CustomerState { extra: vec![PacketS::ReplaceHand { player: me, item: demand.output, - hand: Hand::Left, + hand: Hand(0), }], ..Default::default() }; @@ -375,7 +375,8 @@ impl CustomerState { if game .players .get(&me) - .is_some_and(|pl| pl.items[Hand::Left.index()].is_none()) + .is_some_and(|pl| pl.items[0].is_none()) + // TODO index out of bounds? { if let Some(path) = find_path(&game.walkable, pos.as_ivec2(), *origin) { *self = CustomerState::Exiting { path }; @@ -390,12 +391,12 @@ impl CustomerState { PacketS::Interact { player: me, pos: Some(*table), - hand: Hand::Left, + hand: Hand(0), }, PacketS::Interact { player: me, pos: None, - hand: Hand::Left, + hand: Hand(0), }, ], direction, diff --git a/server/bot/src/algos/simple.rs b/server/bot/src/algos/simple.rs index 5a7e61a0..452f59d3 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, Hand, ItemIndex, Message, PlayerID, Recipe, RecipeIndex, TileIndex, + glam::IVec2, ItemIndex, Message, PlayerID, Recipe, RecipeIndex, TileIndex, }; use log::{debug, warn}; @@ -106,17 +106,16 @@ impl State for Simple { impl Context<'_, S> { pub fn is_hand_item(&self, item: ItemIndex) -> bool { - self.game.players.get(&self.me).is_some_and(|p| { - p.items[Hand::Left.index()] - .as_ref() - .is_some_and(|i| i.kind == item) - }) + self.game + .players + .get(&self.me) + .is_some_and(|p| p.items[0].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.items[Hand::Left.index()].is_some()) + .map(|p| p.items[0].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 0ffbf4b6..918be7e1 100644 --- a/server/bot/src/main.rs +++ b/server/bot/src/main.rs @@ -109,7 +109,7 @@ fn main() -> Result<()> { network.queue_out.push_back(PacketS::Interact { player: b.id, pos: interact, - hand: Hand::Left, + hand: Hand(0), }) } network.queue_out.push_back(PacketS::Movement { diff --git a/server/client-lib/src/lib.rs b/server/client-lib/src/lib.rs index 54c7cd6e..a40eafc1 100644 --- a/server/client-lib/src/lib.rs +++ b/server/client-lib/src/lib.rs @@ -20,7 +20,8 @@ pub mod network; pub mod spatial_index; use hurrycurry_protocol::{ - glam::IVec2, movement::MovementBase, Gamedata, Hand, 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,7 +55,7 @@ pub struct Player { pub class: PlayerClass, pub character: i32, pub interacting: Option<(IVec2, Hand)>, - pub items: [Option; 2], + pub items: Vec>, pub communicate_persist: Option<(Message, MessageTimeout)>, pub movement: MovementBase, @@ -94,7 +95,7 @@ impl Game { character, class, interacting: None, - items: [const { None }; 2], + items: (0..self.data.hand_count).map(|_| None).collect(), communicate_persist: None, movement: MovementBase::new(position), }, @@ -116,15 +117,27 @@ impl Game { p.movement.rotation = rot; } } - PacketC::MoveItem { from, to } => { - *self.get_item(to) = self.get_item(from).take(); + if let Some(item) = self.get_item(to).map(|e| e.take()) { + if let Some(to) = self.get_item(from) { + *to = item; + } else { + // TODO perhaps restore to original position? + } + } } PacketC::SetItem { location, item } => { - *self.get_item(location) = item.map(|kind| Item { kind, active: None }); + let location = self.get_item(location); + if let Some(location) = location { + *location = item.map(|kind| Item { kind, active: None }); + } } PacketC::ClearProgress { item } => { - self.get_item(item).as_mut().unwrap().active = None; + if let Some(slot) = self.get_item(item) { + if let Some(item) = slot { + item.active = None; + } + } } PacketC::SetProgress { item, @@ -133,13 +146,17 @@ impl Game { speed, warn, } => { - self.get_item(item).as_mut().unwrap().active = Some(Involvement { - player, - speed, - warn, - position, - recipe: RecipeIndex(0), - }); + if let Some(slot) = self.get_item(item) { + if let Some(item) = slot { + item.active = Some(Involvement { + player, + speed, + warn, + position, + recipe: RecipeIndex(0), + }); + } + } } PacketC::UpdateMap { tile, @@ -224,11 +241,11 @@ impl Game { }); } - pub fn get_item(&mut self, location: ItemLocation) -> &mut Option { + pub fn get_item(&mut self, location: ItemLocation) -> Option<&mut Option> { match location { - ItemLocation::Tile(pos) => &mut self.tiles.get_mut(&pos).unwrap().item, + ItemLocation::Tile(pos) => Some(&mut self.tiles.get_mut(&pos)?.item), ItemLocation::Player(pid, hand) => { - &mut self.players.get_mut(&pid).unwrap().items[hand.index()] + Some(self.players.get_mut(&pid)?.items.get_mut(hand.0)?) } } } diff --git a/server/protocol/src/helpers.rs b/server/protocol/src/helpers.rs index 21835101..b85c2f84 100644 --- a/server/protocol/src/helpers.rs +++ b/server/protocol/src/helpers.rs @@ -106,26 +106,7 @@ impl Display for ItemLocation { 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, - } + write!(f, "h{}", self.0) } } diff --git a/server/protocol/src/lib.rs b/server/protocol/src/lib.rs index 5c7ddeb5..74d463a1 100644 --- a/server/protocol/src/lib.rs +++ b/server/protocol/src/lib.rs @@ -72,11 +72,8 @@ pub struct RecipeIndex(pub usize); pub struct DemandIndex(pub usize); #[derive(Debug, Clone, Copy, Serialize, Deserialize, Encode, Decode, PartialEq, Eq, Hash)] -#[serde(rename_all = "snake_case")] -pub enum Hand { - Left, - Right, -} +#[serde(transparent)] +pub struct Hand(pub usize); #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] pub struct MapMetadata { @@ -105,6 +102,7 @@ pub struct Gamedata { pub bot_algos: Vec, pub recipes: Vec, pub demands: Vec, + pub hand_count: usize, } #[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)] diff --git a/server/src/data/mod.rs b/server/src/data/mod.rs index 57051fe9..15fdfa6b 100644 --- a/server/src/data/mod.rs +++ b/server/src/data/mod.rs @@ -314,6 +314,7 @@ pub fn build_data( item_names, demands, tile_names, + hand_count: 2, }, Serverdata { initial_map, diff --git a/server/src/entity/bot.rs b/server/src/entity/bot.rs index 368f8c9d..6e6c9162 100644 --- a/server/src/entity/bot.rs +++ b/server/src/entity/bot.rs @@ -72,7 +72,7 @@ impl Entity for BotDriver { c.packet_in.push_back(PacketS::Interact { player: self.id, pos: input.interact, - hand: Hand::Left, + hand: Hand(0), }) } c.packet_in.push_back(PacketS::Movement { diff --git a/server/src/server.rs b/server/src/server.rs index 19153864..0889cd71 100644 --- a/server/src/server.rs +++ b/server/src/server.rs @@ -164,10 +164,9 @@ impl GameServerExt for Game { name: player.name.clone(), }); 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), + location: ItemLocation::Player(id, Hand(i)), item: Some(item.kind), }); if let Some(Involvement { @@ -180,7 +179,7 @@ impl GameServerExt for Game { { out.push(PacketC::SetProgress { player, - item: ItemLocation::Player(id, hand), + item: ItemLocation::Player(id, Hand(i)), position, speed, warn, @@ -255,7 +254,7 @@ impl GameServerExt for Game { self.players.insert( id, Player { - items: [const { None }; 2], + items: (0..self.data.hand_count).map(|_| None).collect(), character, class, movement: MovementBase::new(position), @@ -531,14 +530,17 @@ impl Server { return Err(tre!("s.error.customer_interact")); } + 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, None, Some(pid), - &mut this.items[hand.index()], + this_hslot, ItemLocation::Player(base_pid, hand), - &mut other.items[hand.index()], + other_hslot, ItemLocation::Player(pid, hand), &mut self.game.score, &mut self.score_changed, @@ -552,6 +554,11 @@ impl Server { .get_mut(&pid) .ok_or(tre!("s.error.no_player"))?; + let hslot = player + .items + .get_mut(hand.0) + .ok_or(tre!("s.error.no_hand"))?; + interact( &self.game.data, edge, @@ -559,7 +566,7 @@ impl Server { Some(pid), &mut tile.item, ItemLocation::Tile(pos), - &mut player.items[hand.index()], + hslot, ItemLocation::Player(pid, hand), &mut self.game.score, &mut self.score_changed, @@ -602,10 +609,12 @@ impl Server { } PacketS::ReplaceHand { item, player, hand } => { let pdata = self.game.players.get_mut(&player).ok_or(tre!(""))?; - pdata.items[hand.index()] = item.map(|i| Item { - kind: i, - active: None, - }); + if let Some(slot) = pdata.items.get_mut(hand.0) { + *slot = item.map(|i| Item { + kind: i, + active: None, + }); + } self.packet_out.push_back(PacketC::SetItem { location: ItemLocation::Player(player, hand), item, @@ -680,7 +689,7 @@ impl Server { &self.gamedata_index, None, item, - ItemLocation::Player(pid, Hand::from_index(i)), + ItemLocation::Player(pid, Hand(i)), &mut self.game.score, &mut self.score_changed, &mut self.packet_out, -- cgit v1.2.3-70-g09d2