(Feat) Item Dqta

This commit is contained in:
2026-06-25 14:40:21 +02:00
parent 3597bacb1a
commit 931bc9c9e2
10 changed files with 372 additions and 20 deletions
+78 -15
View File
@@ -131,7 +131,13 @@ namespace Ashwild.Inventory
/// Server-side: sends a granted item to this inventory's owning client, where it is added.
/// Called after the server authorises a pickup.
/// </summary>
public void GrantItemFromServer(ItemData item, int quantity)
public void GrantItemFromServer(ItemData item, int quantity) => GrantItemFromServer(item, quantity, -1);
/// <summary>
/// Server-side grant that also restores a specific remaining-uses value, used when a partially
/// used instance is picked back up off the ground. A negative value means "grant at full uses".
/// </summary>
public void GrantItemFromServer(ItemData item, int quantity, int uses)
{
if (item == null) return;
@@ -142,14 +148,15 @@ namespace Ashwild.Inventory
return;
}
TargetGrantItem(Owner, id, quantity);
TargetGrantItem(Owner, id, quantity, uses);
}
/// <summary>
/// Runs on the owning client: resolves the granted item and adds it locally.
/// Runs on the owning client: resolves the granted item and adds it locally, restoring its
/// remaining uses when one was carried across the drop.
/// </summary>
[TargetRpc]
private void TargetGrantItem(NetworkConnection conn, ushort itemId, int quantity)
private void TargetGrantItem(NetworkConnection conn, ushort itemId, int quantity, int uses)
{
ItemData item = ItemDatabase.Instance != null ? ItemDatabase.Instance.GetItem(itemId) : null;
if (item == null)
@@ -158,7 +165,7 @@ namespace Ashwild.Inventory
return;
}
AddItem(item, quantity);
AddItem(item, quantity, uses);
}
#endregion
@@ -173,7 +180,12 @@ namespace Ashwild.Inventory
public InventorySlot GetSelectedSlot() => slots[selectedHotbarIndex];
public bool AddItem(ItemData item, int quantity = 1)
/// <summary>
/// Adds an item, stacking into existing slots first. Uses-tracked items never stack: each unit
/// takes its own slot with its own uses bar. The optional uses value restores a partially used
/// instance (negative = full); it only applies to uses-tracked items.
/// </summary>
public bool AddItem(ItemData item, int quantity = 1, int uses = -1)
{
if (item == null)
{
@@ -183,21 +195,32 @@ namespace Ashwild.Inventory
int remaining = quantity;
for (int i = 0; i < inventorySize && remaining > 0; i++)
if (!item.HasUses)
{
if (!slots[i].IsEmpty && slots[i].ItemData == item && slots[i].CanAccept(item))
for (int i = 0; i < inventorySize && remaining > 0; i++)
{
remaining = slots[i].AddQuantity(remaining);
NotifySlotChanged(i);
if (!slots[i].IsEmpty && slots[i].ItemData == item && slots[i].CanAccept(item))
{
remaining = slots[i].AddQuantity(remaining);
NotifySlotChanged(i);
}
}
}
for (int i = 0; i < inventorySize && remaining > 0; i++)
{
if (slots[i].IsEmpty)
{
int toPlace = (item.IsStackable && remaining > item.MaxStackSize) ? item.MaxStackSize : remaining;
slots[i].Set(item, toPlace);
remaining -= toPlace;
if (item.HasUses)
{
slots[i].Set(item, 1, uses);
remaining -= 1;
}
else
{
int toPlace = (item.IsStackable && remaining > item.MaxStackSize) ? item.MaxStackSize : remaining;
slots[i].Set(item, toPlace);
remaining -= toPlace;
}
NotifySlotChanged(i);
}
}
@@ -257,6 +280,12 @@ namespace Ashwild.Inventory
NotifySlotChanged(indexB);
}
/// <summary>
/// Consumes one use of a consumable: applies its restores once (per bite, for multi-use food)
/// then either spends a use or removes one unit. A multi-use item is kept at 0 uses (red,
/// unusable) when KeepWhenDepleted is set, otherwise it is destroyed. Ignores an already
/// depleted item.
/// </summary>
public void UseItem(int index)
{
if (index < 0 || index >= inventorySize) return;
@@ -264,6 +293,7 @@ namespace Ashwild.Inventory
ItemData item = slots[index].ItemData;
if (item.ItemType != ItemType.Consumable) return;
if (slots[index].IsDepleted) return;
if (PlayerStats.Instance != null)
{
@@ -273,7 +303,39 @@ namespace Ashwild.Inventory
}
PlayerEvents.RaiseItemConsumed(item);
RemoveItem(index, 1);
if (item.HasUses)
{
slots[index].ConsumeUse(1);
if (slots[index].IsDepleted && !item.KeepWhenDepleted)
RemoveItem(index, 1);
else
NotifySlotChanged(index);
}
else
{
RemoveItem(index, 1);
}
}
/// <summary>
/// Spends durability on the currently selected hotbar item after a successful tool hit. The
/// tool is kept at 0 uses (red, unusable until repaired) when KeepWhenDepleted is set, otherwise
/// it is destroyed. Returns false when the selected slot holds a depleted repairable tool, so
/// the caller can block the swing; true otherwise (including non-uses items).
/// </summary>
public bool ConsumeSelectedToolUse(int amount = 1)
{
InventorySlot slot = slots[selectedHotbarIndex];
if (slot.IsEmpty || !slot.ItemData.HasUses) return true;
if (slot.IsDepleted) return false;
ItemData item = slot.ItemData;
slot.ConsumeUse(amount);
if (slot.IsDepleted && !item.KeepWhenDepleted)
RemoveItem(selectedHotbarIndex, 1);
else
NotifySlotChanged(selectedHotbarIndex);
return true;
}
public void DropItem(int index, int quantity = 1)
@@ -282,13 +344,14 @@ namespace Ashwild.Inventory
if (slots[index].IsEmpty) return;
ItemData item = slots[index].ItemData;
int uses = item.HasUses ? slots[index].CurrentUses : -1;
Transform origin = dropOrigin != null ? dropOrigin : transform;
if (item.WorldPrefab != null && origin != null && PickableRegistry.Instance != null)
{
Vector3 dropPos = origin.position + origin.forward * dropForwardDistance;
ushort id = ItemDatabase.Instance != null ? ItemDatabase.Instance.GetId(item) : (ushort)0;
if (id != 0)
PickableRegistry.Instance.RequestDropServerRpc(id, quantity, dropPos, origin.rotation);
PickableRegistry.Instance.RequestDropServerRpc(id, quantity, uses, dropPos, origin.rotation);
else
Debug.LogWarning($"[PlayerInventory] '{item.ItemName}' is not in the ItemDatabase — drop not spawned. Run Rebuild Item Database.", this);
}