Zum Inhalt

Inventar-System (cv_inventory)

React/NUI-Inventar mit Slots, Gewichtslimit, Waffenslots und optionalem Sekundär-Container (Camper-Lager, Truhe).


Architektur

cv_inventory
  ├─ NUI (React)     – Slot-Grid, Drag & Drop, Waffenrad-Zuweisung
  └─ Server (Lua)
       ├─ BuildInventoryPayload(charId)          – Haupt-Inventar aufbauen
       ├─ BuildContainerInventoryPayload(id)     – Container aufbauen
       ├─ GetActiveSecondaryContainer(source)    – aktiver Sekundär-Container
       └─ Events / Callbacks für Slot-Operationen

Inventar öffnen

Das Inventar wird über einen Tastendruck geöffnet (Standard: I). Der Client sendet cv_inventory:requestInventory an den Server, der das komplette Payload zurückschickt:

Server → Client: 'cv_inventory:updateInventory'
Payload:
{
    slots         – { [slotNr] = slotPayload }
    weight        – aktuelles Gewicht
    maxWeight     – maximales Gewicht
    maxSlots      – maximale Slot-Anzahl
    weaponSlots   – { [slotType] = weaponData }
    weaponSlotsConfig
    secondary?    – { slots, weight, maxWeight, maxSlots, containerId, title }
}

Framework-Exports (verwendet intern)

Die eigentliche Inventar-Logik liegt im cv_framework und wird über Exports aufgerufen:

-- Inventar eines Charakters lesen
exports["cv_framework"]:GetCharacterInventory(charId)  -- → item[]

-- Einzelnen Slot lesen
exports["cv_framework"]:GetSlotItem(charId, slot)  -- → { item_name, quantity, slot, ... }

-- Item zu Inventar hinzufügen
cv.inventory.addItem(charId, itemName, quantity, metadata)  -- → boolean

-- Item entfernen
cv.inventory.removeItem(charId, itemName, quantity)  -- → boolean

-- Prüfen ob Item vorhanden
cv.inventory.hasItem(charId, itemName, quantity)  -- → boolean

-- Platz prüfen (Gewicht + Slots)
cv.inventory.canAddItem(charId, itemName, quantity)  -- → boolean, reason

-- Slot-Payload bauen (für NUI-Darstellung)
exports["cv_framework"]:BuildSlotPayload(itemName, { quantity, durability, metadata }, slot)

-- Gewichts-/Slot-Limit
exports["cv_framework"]:GetInventoryMaxWeight()        -- → number
exports["cv_framework"]:GetInventoryDefaultSlotCount() -- → number

Container (Lager / Truhen)

Ein Sekundär-Container kann parallel zum Spieler-Inventar geöffnet werden:

-- Container-Inventar lesen
exports["cv_framework"]:GetContainerInventory(containerId)  -- → item[]

-- Container konfigurieren (z.B. beim Erstellen)
exports["cv_framework"]:GetCustomInventoryConfig(containerId)
-- → { maxWeight, maxSlots, containerType, ... }

-- Items in Container
cv.inventory.addContainerItem(containerId, containerType, itemName, qty, metadata)
cv.inventory.removeContainerItem(containerId, itemName, qty)
cv.inventory.hasContainerItem(containerId, itemName, qty)
cv.inventory.canAddContainerItem(containerId, itemName, qty)
cv.inventory.getContainerSlotItem(containerId, slot)

Sekundär-Context setzen (Server-Event)

-- Aus anderer Ressource: Öffnet Container als zweites Inventar-Panel
TriggerClientEvent('cv_inventory:setSecondaryContext', source, {
    type        = 'custom',   -- 'custom', 'vehicle_trunk', ...
    containerId = 'mein-container-id',
    title       = 'WERKZEUGKISTE'
})

-- Context wieder entfernen
TriggerClientEvent('cv_inventory:clearSecondaryContext', source)
-- oder Server-Event:
TriggerServerEvent('cv_inventory:clearSecondaryContext')

Waffenslots

Waffen können in bis zu 3 dedizierten Slots (Holster) eingetragen werden:

-- Waffenslots eines Charakters lesen
exports["cv_framework"]:GetCharacterWeaponSlots(charId)
-- → { [slotType] = { itemName, ammo, durability, inventorySlot, metadata } }

-- Waffe einem Slot zuweisen
exports["cv_framework"]:AssignWeaponToSlot(source, slotType, inventorySlot)

-- Waffe aus Slot entfernen
exports["cv_framework"]:RemoveWeaponFromSlot(source, slotType, restoreToInventory)

-- Munition speichern
exports["cv_framework"]:SaveAllWeaponSlotAmmo(charId, source)

-- Status
exports["cv_framework"]:IsWeaponSlotsEnabled()   -- → boolean
exports["cv_framework"]:GetWeaponSlotsConfig()   -- → table

Munitions-Sync: Der Client sendet periodisch cv:server:SyncWeaponAmmo { [slotType] = ammo }. Der Server akzeptiert nur gleiche oder niedrigere Werte (verhindert Cheating).


Exports aus cv_inventory

-- Camper/Instanzlager direkt befüllen (aus anderen Ressourcen)
exports['cv_inventory']:StoreItemInPlayerInstanceInventory(playerSource, itemName, amount)
-- → boolean, errorMessage

-- Item aus Camper/Instanzlager nehmen
exports['cv_inventory']:TakeItemFromPlayerInstanceInventory(playerSource, itemName, amount)
-- → boolean, errorMessage

-- Waffenslots für Charakter deaktivieren (temporär, bis Relog)
exports['cv_inventory']:DisableWeaponSlots(charId)
exports['cv_inventory']:EnableWeaponSlots(charId)
exports['cv_inventory']:IsWeaponSlotsDisabled(charId)  -- → boolean

-- Container-Payload für externe NUI bauen
exports['cv_inventory']:BuildContainerInventoryPayload(containerId)

Relevante Events

Event Richtung Beschreibung
cv_inventory:requestInventory Client → Server Inventar laden
cv_inventory:updateInventory Server → Client Inventar-Payload senden
cv_inventory:setSecondaryContext Client → Server Sekundär-Container setzen
cv_inventory:clearSecondaryContext Client → Server Sekundär-Container entfernen
cv:server:SwapSecondaryInventorySlots Client → Server Slots im Container tauschen
cv:server:MoveBetweenInventories Client → Server Item zwischen Inventar und Container verschieben
cv:server:AssignWeaponSlot Client → Server Waffe einem Waffenslot zuweisen
cv:server:RemoveWeaponSlot Client → Server Waffe aus Waffenslot entfernen
cv:server:SyncWeaponAmmo Client → Server Munitionsstand synchronisieren
cv:client:SyncWeaponWheel Server → Client Waffenrad-Status senden