// Copyright ExByte Studios. Item Interaction Ecosystem. #include "ItemCraftingLibrary.h" #include "ItemInventoryLog.h" #include "InventoryComponent.h" #include "ItemDatabaseSubsystem.h" #include "ItemContentRows.h" bool UItemCraftingLibrary::CanCraft(const UObject* WorldContext, UInventoryComponent* Inventory, FName RecipeId, FGameplayTag AvailableStation) { const UItemDatabaseSubsystem* DB = UItemDatabaseSubsystem::Get(WorldContext); if (!DB || !Inventory) { return false; } FCraftingRecipeRow Recipe; if (!DB->FindRecipe(RecipeId, Recipe)) { return false; } if (Recipe.StationTag.IsValid() && !AvailableStation.MatchesTag(Recipe.StationTag)) { return false; } for (const FCraftingIngredient& In : Recipe.Inputs) { if (Inventory->GetItemCount(In.ItemId) < In.Quantity) { return false; } } return true; } bool UItemCraftingLibrary::Craft(const UObject* WorldContext, UInventoryComponent* Inventory, FName RecipeId, FGameplayTag AvailableStation) { if (!Inventory || !Inventory->GetOwner() || !Inventory->GetOwner()->HasAuthority()) { return false; } if (!CanCraft(WorldContext, Inventory, RecipeId, AvailableStation)) { return false; } const UItemDatabaseSubsystem* DB = UItemDatabaseSubsystem::Get(WorldContext); FCraftingRecipeRow Recipe; DB->FindRecipe(RecipeId, Recipe); // Consume inputs (already verified present). for (const FCraftingIngredient& In : Recipe.Inputs) { if (!ConsumeItem(Inventory, In.ItemId, In.Quantity)) { UE_LOG(LogItemInventory, Error, TEXT("Craft '%s' failed mid-consume for %s."), *RecipeId.ToString(), *In.ItemId.ToString()); return false; } } FItemInstanceData Output = DB->MakeItemInstance(Recipe.OutputItemId, FMath::Max(1, Recipe.OutputQuantity)); Inventory->AddItem(Output); UE_LOG(LogItemInventory, Log, TEXT("[Crafting] crafted %s"), *Recipe.OutputItemId.ToString()); return true; } void UItemCraftingLibrary::RollLootIntoInventory(const UObject* WorldContext, UInventoryComponent* Inventory, FName TableId, int32 RollCount) { const UItemDatabaseSubsystem* DB = UItemDatabaseSubsystem::Get(WorldContext); if (!DB || !Inventory || !Inventory->GetOwner() || !Inventory->GetOwner()->HasAuthority()) { return; } TArray Loot; DB->RollLoot(TableId, RollCount, Loot); for (FItemInstanceData& Item : Loot) { Inventory->AddItem(Item); } } bool UItemCraftingLibrary::ConsumeItem(UInventoryComponent* Inventory, FName ItemId, int32 Count) { int32 Remaining = Count; TArray Items; Inventory->GetAllItems(Items); for (const FItemInstanceData& Item : Items) { if (Remaining <= 0) { break; } if (Item.ItemId != ItemId || Item.Lock.bLocked) { continue; } const int32 Take = FMath::Min(Remaining, Item.Quantity); if (Inventory->RemoveQuantity(Item.InstanceId, Take)) { Remaining -= Take; } } return Remaining <= 0; }