diff options
| -rw-r--r-- | client/game.gd | 14 | ||||
| -rw-r--r-- | client/global.gd | 9 | ||||
| -rw-r--r-- | client/multiplayer.gd | 3 | ||||
| -rw-r--r-- | client/player/controllable_player.gd | 12 | ||||
| -rw-r--r-- | client/player/player.gd | 31 | ||||
| -rw-r--r-- | locale/en.ini | 1 | ||||
| -rw-r--r-- | pixel-client/src/game.rs | 50 | ||||
| -rw-r--r-- | server/bot/src/algos/customer.rs | 13 | ||||
| -rw-r--r-- | server/bot/src/algos/simple.rs | 13 | ||||
| -rw-r--r-- | server/bot/src/main.rs | 2 | ||||
| -rw-r--r-- | server/client-lib/src/lib.rs | 51 | ||||
| -rw-r--r-- | server/protocol/src/helpers.rs | 21 | ||||
| -rw-r--r-- | server/protocol/src/lib.rs | 8 | ||||
| -rw-r--r-- | server/src/data/mod.rs | 1 | ||||
| -rw-r--r-- | server/src/entity/bot.rs | 2 | ||||
| -rw-r--r-- | server/src/server.rs | 33 | 
16 files changed, 144 insertions, 120 deletions
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 e1013727..63ffa715 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<Item> { +    pub fn get_item(&mut self, location: ItemLocation) -> Option<&mut Option<Item>> {          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<S> 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<Item>; 2], +    pub items: Vec<Option<Item>>,      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<Item> { +    pub fn get_item(&mut self, location: ItemLocation) -> Option<&mut Option<Item>> {          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<String>,      pub recipes: Vec<Recipe>,      pub demands: Vec<Demand>, +    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<T: BotAlgo + Any> Entity for BotDriver<T> {              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 9b90d6b3..f59cd2b9 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), @@ -527,14 +526,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, @@ -548,6 +550,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, @@ -555,7 +562,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, @@ -598,10 +605,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, @@ -676,7 +685,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,  |