Repository navigation
Player inventory
The Player Inventory System manages items owned by the player. It uses a slot-based grid to support item storage, stacking, selection, hotbar access, and inventory expansion.
By default, the inventory contains 3 rows × 8 columns (24 slots). The first row is used as the player's hotbar.
The main component responsible for inventory state and operations, including:
- Adding and removing items
- Item selection
- Item sorting by Itemid
- Inventory capacity
- Slot swapping and expansion
Represents one physical inventory slot containing an ItemType and its quantity. Empty slots contain no item.
Displays the first row of the inventory as the player's hotbar.
Displays the complete inventory grid and selected item information.
The inventory stores its slots using:
List<InventorySlot> slots;Items of the same ItemType are stacked together. New item types are placed into the first available empty slot.
The first inventory row acts as the hotbar:
┌────┬────┬────┬────┬────┬────┬────┬────┐
│ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ Hotbar
├────┼────┼────┼────┼────┼────┼────┼────┤
│ │ │ │ │ │ │ │ │
├────┼────┼────┼────┼────┼────┼────┼────┤
│ │ │ │ │ │ │ │ │
└────┴────┴────┴────┴────┴────┴────┴────┘
Inventory changes trigger inventoryChanged, while selection changes trigger inventorySelectionChanged. UI components listen to these events and update automatically.
classDiagram
class InventoryComponent {
-List~InventorySlot~ slots
-int rows
-int columns
-int selectedSlotIndex
+addItem(ItemType, int) boolean
+removeItem(ItemType, int) boolean
+selectSlot(int)
+selectNext()
+selectPrevious()
+swapSlots(int, int)
+sortByItemId()
}
class InventorySlot {
-ItemType itemType
-int quantity
+getItemType() ItemType
+getQuantity() int
+isEmpty() boolean
}
InventoryComponent "1" *-- "*" InventorySlot
| Method | Purpose |
|---|---|
addItem(item, quantity) |
Add items to the inventory |
removeItem(item, quantity) |
Remove items |
getItemCount(item) |
Get an item's quantity |
hasItem(item) |
Check whether an item exists |
selectSlot(index) |
Select a specific slot |
selectNext() / selectPrevious()
|
Cycle between owned items |
swapSlots(a, b) |
Swap two inventory slots |
sortByItemId() |
Sort item by itemid |
addRow() / addColumn()
|
Expand the inventory |
InventoryComponent inventory = new InventoryComponent(0);
inventory.addItem(ItemType.ARROW, 10);
inventory.addItem(ItemType.RopeArrow, 1);
inventory.selectSlot(0);
int arrows = inventory.getItemCount(ItemType.ARROW);
inventory.removeItem(ItemType.ARROW, 1);Automated tests cover the inventory, item-use, player-interaction, and ranged-combat systems.
InventoryComponentTest verifies:
- Adding, stacking, and removing items
- Inventory capacity and invalid quantities
- Item selection, switching, and sorting
- Slot swapping and selection preservation
- Row and column expansion
- Quick-slot selection
- Invalid and no-op inventory operations
- Inventory and selection change events
PlayerInteractionComponentTest verifies:
- Detecting the nearest item within interaction range
- Ignoring non-item and out-of-range entities
- Picking up items and handling a full inventory
- Dropping the complete selected item stack
- Permanently deleting the complete selected item stack
- Rejecting drop or delete operations when no item is selected
- Switching between owned items
- Emitting the appropriate success and failure events
ItemUseComponentTest verifies:
- Standard arrows are consumed when fired
- A projectile attack event is produced for a valid standard-arrow attack
- The player cannot attack without owning and selecting an item
- Health potions heal the player and are consumed
- Potions cannot be used at full health
- Rope Arrows are not consumed
- Rope Arrow cooldown is applied and enforced
KeyboardPlayerInputComponentTest verifies:
-
Eproduces only one attack per key press - Attacks use the current mouse aim direction
- The player cannot bypass inventory validation when
ItemUseComponentis missing -
Rdrops the selected stack -
Deleteremoves the selected stack - Movement, jumping, sprinting, and grapple input events
GrappleComponentTest, BowComponentTest, and
ArrowProjectileComponentTest verify:
- Grappling is rejected when the player does not own a Rope Arrow
- Grappling succeeds without consuming an owned Rope Arrow
- Bow attacks create projectiles in the requested direction
- Projectiles damage valid targets only once
- Projectiles expire when hitting terrain or obstacles
- Projectile range and movement behaviour
The following behaviours should also be checked during gameplay:
-
Fpicks up the nearest item within range -
Edoes nothing when no owned arrow is selected - Standard arrows visibly spawn and damage a target
-
Rcreates a dropped world item containing the complete selected stack -
Deleteremoves the selected stack without spawning a world item - Rope grappling only works while a Rope Arrow is owned
- Inventory and hotbar displays refresh after pickup, use, drop, and deletion
- Attack, item-use, and failure audio/visual feedback appears at the correct time
- Fire Arrow and Cold Arrow attributes are unit tested, but their complete attack-effect pipelines are not yet covered by integration tests.
From the source directory:
./gradlew core:testEntities and Components
Input Handling
Arrow Selection Wheel Arrow Selection Wheel — Sprint 3