Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/TaylorZaneKirk/MMO-Project/llms.txt

Use this file to discover all available pages before exploring further.

All inventory and equipment mutations in MMO Project are server-authoritative. Clients send intent messages — use item, drop item, pick up a ground item, or unequip a piece of equipment. The server validates the intent, applies the change in a database transaction, and persists the result before broadcasting the authoritative response. No inventory state is applied client-side before the server reply arrives.

Supported actions

Use Item

Routes by item type: equippable items are handled via TryEquipInventoryItemAsync; food items restore health and decrement the stack. Unknown or unsupported actions are rejected.

Drop Item

Removes the item from character_inventory and creates a ground_items row at the character’s current tile. Immediately visible to the owner; hidden from others until the private visibility window expires.

Pick Up Ground Item

Validates that the character is standing on the item’s tile and that inventory has space. Moves the item from ground_items into character_inventory.

Unequip Item

Validates the target slot is occupied and that at least one inventory slot is open. Moves the item from the equipment slot into inventory.

Inventory item use

InventoryItemUseService.UseInventoryItemAsync handles the primary use action. Non-primary use actions are rejected immediately with use_status: unsupported_use_action. For a valid request the service loads the inventory item by slot index. If the slot is empty it returns use_status: missing_inventory_item. Otherwise, it routes by item name:
  • Food items — if the item name matches a built-in FoodRestoreDefinition (e.g. Apple, Pie, Orc Burger), the service calls TryConsumeFoodItemAsync, which decrements the stack, applies a randomized health restore within the item’s defined range, and returns a chat_message. The result carries routed_behavior: consume_food and health_restored.
  • Equippable items — any item not matched as food falls through to TryEquipInventoryItemAsync. The result carries routed_behavior: equip.
// InventoryItemUseResult carries the routing decision and optional outcomes
public sealed record InventoryItemUseResult(
    string UseStatus,
    string UseAction,
    int InventorySlotIndex,
    string? ItemId,
    string? ItemName,
    string? RoutedBehavior,
    string? EquipmentSlotId,
    string? UnequippedItemId,
    int? HealthRestored = null,
    string? ChatMessage = null);
A successful use emits runtime events: equip emits InventoryChangedEvent and EquipmentChangedEvent; consume_food emits InventoryChangedEvent and CharacterStatusChangedEvent.

Item drop

InventoryItemDropService.DropInventoryItemAsync runs inside an IInventoryGroundItemTransactionRunner to keep the inventory removal and ground-item insertion atomic. The service:
  1. Loads and locks the character’s map_presence. Returns drop_status: MissingPresence if absent.
  2. Loads and locks the inventory item by slot index. Returns drop_status: MissingInventoryItem if absent.
  3. Deletes the character_inventory row.
  4. Inserts a new ground_items row at the character’s current tile, stamping dropped_at and visible_to_others_at = dropped_at + DroppedItemPrivateVisibilitySeconds.
// inventory_item_drop_response payload (key fields)
{
  "drop_status": "Succeeded",
  "inventory_slot_index": 3,
  "ground_item_id": "e3a1...",
  "item_id": "apple",
  "item_name": "Apple",
  "map_id": "x1000y992",
  "tile_x": 5,
  "tile_y": 3,
  "stack_count": 1
}
On success the service emits InventoryChangedEvent and GroundItemSpawnedEvent.

Ground item pickup

GroundItemPickupService.PickupGroundItemAsync also runs inside the transactional runner. The validation sequence is:
  1. Load and lock the ground_items row. Return pickup_status: MissingGroundItem if not found.
  2. If the character is not the owner and visible_to_others_at is still in the future, return pickup_status: NotVisible.
  3. Load and lock the character’s map_presence. Return pickup_status: NotAtItemTile if the character is not on the exact tile where the item lies.
  4. Find a merge slot (existing stack of the same item) or the first open slot. Return pickup_status: InventoryFull if neither exists.
  5. Call AddInventoryItemAsync then DeleteGroundItemAsync.
public sealed record GroundItemPickupResult(
    GroundItemPickupStatus Status,
    string GroundItemId,
    GroundItemPickupFacts? Facts);
A successful pickup emits InventoryChangedEvent and GroundItemRemovedEvent.

Unequip

EquipmentItemUnequipService.UnequipEquipmentItemAsync delegates to CharacterEquipmentRepository.TryUnequipEquipmentItemAsync, which validates the target slot is occupied and finds the first available inventory slot before moving the item. The response carries unequip_status: ok on success or unequip_status: inventory_full if no slot is available.
public sealed record EquipmentItemUnequipResult(
    string UnequipStatus,
    string EquipmentSlotId,
    string? ItemId,
    int? InventorySlotIndex);
A successful unequip emits InventoryChangedEvent and EquipmentChangedEvent.

InventoryRules

InventoryRules is the canonical source of shared inventory constraints:
public static class InventoryRules
{
    public const int DefaultCapacity = 28;
}
GroundItemPickupService and any other service that checks available slots reads InventoryRules.DefaultCapacity to keep the limit consistent. Stack count management and merge-slot logic live in the repository layer but are bounded by this constant.

Skill requirements

Equipment items carry skill_requirements and skill_modifiers arrays. Before equipping, the server checks the character’s base skill values against each entry in item_skill_requirements. A character whose base skill is below the required threshold cannot equip the item. Equipment modifiers adjust the character’s effective skill values reported in the world_snapshot and are visible in the client’s skill panel, but modifiers from currently-equipped items do not count toward satisfying the requirements of a new item being equipped.

Ground item visibility

When an item is dropped, visible_to_others_at is set to dropped_at + DroppedItemPrivateVisibilitySeconds. The owner can see and pick up the item immediately. Other characters do not see the item in world_snapshot.ground_items until the visibility window has elapsed. GroundItemVisibilityWorker polls every second for items whose visible_to_others_at has passed and not yet been broadcast. For each such item it allocates a new map_revision and broadcasts a ground_item_spawned message to all delta clients on the map, then triggers a legacy snapshot refresh for non-delta clients.
All inventory mutations must go through the server. Never apply inventory changes client-side before receiving the authoritative response.

Build docs developers (and LLMs) love