Files
inventory-system-plugin/Source/ItemInventory/Private/ItemCraftingLibrary.cpp
Bonchellon 7f7e043a88 Initial commit: Item Interaction Ecosystem plugin (UE5.7)
Server-authoritative, data-driven item/inventory/interaction/carry/equipment/
world-slot/placement/crafting framework. 8 modules, compiles against UE 5.7.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:49:56 +03:00

99 lines
2.8 KiB
C++

// 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<FItemInstanceData> 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<FItemInstanceData> 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;
}