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>
This commit is contained in:
98
Source/ItemInventory/Private/ItemCraftingLibrary.cpp
Normal file
98
Source/ItemInventory/Private/ItemCraftingLibrary.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
// 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;
|
||||
}
|
||||
Reference in New Issue
Block a user