Skip to content

Player inventory

wei weng edited this page Sep 2, 2026 · 4 revisions

Player Inventory

Introduction

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.


Key Components

InventoryComponent

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

InventorySlot

Represents one physical inventory slot containing an ItemType and its quantity. Empty slots contain no item.

InventoryBarDisplay

Displays the first row of the inventory as the player's hotbar.

BackpackDisplay

Displays the complete inventory grid and selected item information.


Implementation

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.

UML Diagram

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
Loading

Usage

Key Public Methods

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

Example Usage

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);

Testing

Automated tests cover the inventory, item-use, player-interaction, and ranged-combat systems.

Inventory

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

Player–Item Interaction

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

Item Use and Attack Restrictions

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

Keyboard Controls

KeyboardPlayerInputComponentTest verifies:

  • E produces only one attack per key press
  • Attacks use the current mouse aim direction
  • The player cannot bypass inventory validation when ItemUseComponent is missing
  • R drops the selected stack
  • Delete removes the selected stack
  • Movement, jumping, sprinting, and grapple input events

Grapple and Projectile Behaviour

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

Manual Integration Testing

The following behaviours should also be checked during gameplay:

  • F picks up the nearest item within range
  • E does nothing when no owned arrow is selected
  • Standard arrows visibly spawn and damage a target
  • R creates a dropped world item containing the complete selected stack
  • Delete removes 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

Known Testing Gaps

  • Fire Arrow and Cold Arrow attributes are unit tested, but their complete attack-effect pipelines are not yet covered by integration tests.

Running the Tests

From the source directory:

./gradlew core:test

Clone this wiki locally