So the cast maps EquipmentSlot.Weapon (0) → ItemEquipSlot.None (0), and every item equips only through the command slot one BELOW its real one:
EquipItemCommand { EquipmentSlot = Weapon } with a weapon (e.g. wooden_staff) → rejected
EquipItemCommand { EquipmentSlot = Armor } with that same weapon → accepted (equipment dict then stores the weapon under Armor)
Impact: clients sending the semantically correct slot can never equip anything; whatever works today works by accident of the off-by-one. Fix by mapping explicitly (switch) or aligning the enums — note EquipmentSlot.Armor is documented "Legacy - maps to Torso", so an explicit mapping function is probably the safe fix.
Until fixed, BaseZoneItemCommandTests pins the current off-by-one behavior as characterization tests referencing this issue — they will fail when the mapping is corrected (then flip the expectations).
Found by the coverage wave (spikersoft-backend PR #454) while testing `BaseZone.ProcessEquipItemCommand`.
`PlayerEntity.EquipItem` (SpikerSoft.Common `IGameEntity.cs` ~line 800) validates with:
```csharp
if (definition.EquipSlot != (ItemEquipSlot)(int)equipSlot && definition.EquipSlot != ItemEquipSlot.None)
return (false, null);
```
But the enums are misaligned by one:
- `EquipmentSlot` (IGameCommand.cs): `Weapon = 0, Armor = 1, HpPotion = 2, MpPotion = 3, ...`
- `ItemEquipSlot` (ItemDefinition.cs): `None = 0, Weapon = 1, Armor = 2, HpPotion = 3, MpPotion = 4`
So the cast maps `EquipmentSlot.Weapon (0)` → `ItemEquipSlot.None (0)`, and every item equips only through the command slot one BELOW its real one:
- `EquipItemCommand { EquipmentSlot = Weapon }` with a weapon (e.g. `wooden_staff`) → **rejected**
- `EquipItemCommand { EquipmentSlot = Armor }` with that same weapon → **accepted** (equipment dict then stores the weapon under `Armor`)
Impact: clients sending the semantically correct slot can never equip anything; whatever works today works by accident of the off-by-one. Fix by mapping explicitly (switch) or aligning the enums — note `EquipmentSlot.Armor` is documented "Legacy - maps to Torso", so an explicit mapping function is probably the safe fix.
Until fixed, `BaseZoneItemCommandTests` pins the current off-by-one behavior as characterization tests referencing this issue — they will fail when the mapping is corrected (then flip the expectations).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found by the coverage wave (spikersoft-backend PR #454) while testing
BaseZone.ProcessEquipItemCommand.PlayerEntity.EquipItem(SpikerSoft.CommonIGameEntity.cs~line 800) validates with:But the enums are misaligned by one:
EquipmentSlot(IGameCommand.cs):Weapon = 0, Armor = 1, HpPotion = 2, MpPotion = 3, ...ItemEquipSlot(ItemDefinition.cs):None = 0, Weapon = 1, Armor = 2, HpPotion = 3, MpPotion = 4So the cast maps
EquipmentSlot.Weapon (0)→ItemEquipSlot.None (0), and every item equips only through the command slot one BELOW its real one:EquipItemCommand { EquipmentSlot = Weapon }with a weapon (e.g.wooden_staff) → rejectedEquipItemCommand { EquipmentSlot = Armor }with that same weapon → accepted (equipment dict then stores the weapon underArmor)Impact: clients sending the semantically correct slot can never equip anything; whatever works today works by accident of the off-by-one. Fix by mapping explicitly (switch) or aligning the enums — note
EquipmentSlot.Armoris documented "Legacy - maps to Torso", so an explicit mapping function is probably the safe fix.Until fixed,
BaseZoneItemCommandTestspins the current off-by-one behavior as characterization tests referencing this issue — they will fail when the mapping is corrected (then flip the expectations).