From c5e692c0510d49106bf9515dd88479ace6e8b5a7 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Fri, 20 Mar 2026 13:18:22 -0500 Subject: [PATCH] Fixing drop/pickup stacking --- game/scenes/Levels/location_level.gd | 3 +- .../InventoryApi/Services/InventoryStore.cs | 41 ++++++++++++++++--- 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/game/scenes/Levels/location_level.gd b/game/scenes/Levels/location_level.gd index a30d1f1..ea56e22 100644 --- a/game/scenes/Levels/location_level.gd +++ b/game/scenes/Levels/location_level.gd @@ -678,8 +678,7 @@ func _on_inventory_pickup_pressed() -> void: _inventory_status_label.text = "Current location is missing an id." return var quantity := int(_quantity_spin_box.value) - var to_slot := int(_target_slot_spin_box.value) - _transfer_item_async(_selected_ground_item_id, "location", location_id, "character", _character_id, to_slot, quantity, "Picked up item.") + _transfer_item_async(_selected_ground_item_id, "location", location_id, "character", _character_id, null, quantity, "Picked up item.") func _on_inventory_refresh_pressed() -> void: diff --git a/microservices/InventoryApi/Services/InventoryStore.cs b/microservices/InventoryApi/Services/InventoryStore.cs index 5c58232..4bd318d 100644 --- a/microservices/InventoryApi/Services/InventoryStore.cs +++ b/microservices/InventoryApi/Services/InventoryStore.cs @@ -328,13 +328,28 @@ public class InventoryStore if (definition is null) return new InventoryMutationResult { Status = InventoryMutationStatus.Invalid }; - var toSlot = req.ToSlot ?? await FindFirstOpenSlotAsync(toOwner.OwnerType, toOwner.OwnerId); - if (toSlot is null) - return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + InventoryItem? target = null; + int? toSlot = req.ToSlot; + if (toSlot is not null) + { + target = await FindItemBySlotAsync(toOwner.OwnerType, toOwner.OwnerId, toSlot.Value); + if (target is not null && !CanMerge(item, target, definition)) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + } + else if (definition.Stackable) + { + target = await FindMergeTargetAsync(toOwner.OwnerType, toOwner.OwnerId, item.ItemKey, definition.MaxStackSize); + if (target is not null) + toSlot = target.Slot; + } - var target = await FindItemBySlotAsync(toOwner.OwnerType, toOwner.OwnerId, toSlot.Value); - if (target is not null && !CanMerge(item, target, definition)) - return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + if (toSlot is null) + { + toSlot = await FindFirstOpenSlotAsync(toOwner.OwnerType, toOwner.OwnerId); + if (toSlot is null) + return new InventoryMutationResult { Status = InventoryMutationStatus.Conflict }; + target = null; + } if (target is not null) { @@ -521,6 +536,20 @@ public class InventoryStore return slot; } + private async Task FindMergeTargetAsync(string ownerType, string ownerId, string itemKey, int maxStackSize) + { + var normalizedItemKey = NormalizeItemKey(itemKey); + return await _items.Find(i => + i.OwnerType == ownerType && + i.OwnerId == ownerId && + i.ItemKey == normalizedItemKey && + i.EquippedSlot == null && + i.Slot != null && + i.Quantity < maxStackSize) + .SortBy(i => i.Slot) + .FirstOrDefaultAsync(); + } + private Task FindItemBySlotAsync(string ownerType, string ownerId, int slot, IClientSessionHandle? session = null) => session is null ? FindItemBySlotNoSessionAsync(ownerType, ownerId, slot)