Files
inventory-system-plugin/Source/ItemDatabase/Public/ItemDatabaseSubsystem.h
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

170 lines
6.1 KiB
C++

// Copyright ExByte Studios. Item Interaction Ecosystem.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "ItemDefinitionRow.h"
#include "ItemAuxiliaryRows.h"
#include "ItemContentRows.h"
#include "ItemInstanceData.h"
#include "ItemDatabaseSubsystem.generated.h"
/** One problem found by ValidateData (section 28). */
USTRUCT(BlueprintType)
struct FItemValidationIssue
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly, Category = "Validation")
FName ItemId;
UPROPERTY(BlueprintReadOnly, Category = "Validation")
FString Message;
UPROPERTY(BlueprintReadOnly, Category = "Validation")
bool bIsError = true;
};
/**
* Authoritative, read-only access point for all static item data (section 35 stage 1).
*
* Loads the configured data tables once, flattens them into fast lookup maps and
* exposes definition/property/feature/interaction queries plus redirect resolution
* and a data validator. Lives on the GameInstance so it is available on both
* server and clients; the tables themselves are never replicated (section 32).
*/
UCLASS()
class ITEMDATABASE_API UItemDatabaseSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
//~ USubsystem
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
/** Convenience accessor from any world context. */
static UItemDatabaseSubsystem* Get(const UObject* WorldContext);
/** (Re)load every configured table and rebuild the lookup caches. */
void RebuildCache();
// --- Definition lookup ---
/** Returns the definition for an item (after redirects), or null if unknown. C++ fast path. */
const FItemDefinitionRow* GetItemDefinition(FName ItemId) const;
UFUNCTION(BlueprintCallable, Category = "Item|Database")
bool FindItemDefinition(FName ItemId, FItemDefinitionRow& OutDefinition) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
bool HasItem(FName ItemId) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
void GetAllItemIds(TArray<FName>& OutItemIds) const;
/** Applies the redirect chain; returns the input unchanged if no redirect exists. */
UFUNCTION(BlueprintPure, Category = "Item|Database")
FName ResolveRedirect(FName ItemId) const;
// --- Instances ---
/**
* Builds a fresh instance of ItemId with a new GUID and its default runtime
* properties applied. The single correct way to mint an item (server-side).
*/
UFUNCTION(BlueprintCallable, Category = "Item|Database")
FItemInstanceData MakeItemInstance(FName ItemId, int32 Quantity = 1) const;
/** Writes the item's default runtime properties into Out (does not clear first). */
void ApplyDefaultProperties(FName ItemId, FItemRuntimeProperties& Out) const;
/** Adds only default properties that are missing (save migration, section 26.2). */
void ApplyMissingDefaultProperties(FName ItemId, FItemRuntimeProperties& Out) const;
/** Current schema version stamped onto fresh/migrated instances. */
static constexpr int32 CurrentItemDataVersion = 1;
/** Applies redirects + version migration to a loaded instance (section 26). */
UFUNCTION(BlueprintCallable, Category = "Item|Database")
void MigrateLoadedItem(UPARAM(ref) FItemInstanceData& Item) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
int32 GetMaxStack(FName ItemId) const;
// --- Auxiliary data ---
void GetPropertyRows(FName ItemId, TArray<FItemPropertyRow>& Out) const;
void GetFeatureRows(FName ItemId, TArray<FItemFeatureRow>& Out) const;
/** Feature rows for one specific feature tag (e.g. all Rotting params of raw_meat). */
void GetFeatureRows(FName ItemId, const FGameplayTag& Feature, TArray<FItemFeatureRow>& Out) const;
void GetInteractionRows(FName ItemId, TArray<FItemInteractionRow>& Out) const;
/** Per-property replication policy default (section 22), or None if unspecified. */
EItemPropertyReplicationPolicy GetPropertyPolicy(FName ItemId, const FGameplayTag& PropertyTag) const;
/** Property tags on an item that are flagged ServerOnly (never sent to clients). */
void GetServerOnlyProperties(FName ItemId, TArray<FGameplayTag>& Out) const;
// --- Containers / world slots / loot / recipes (section 6) ---
UFUNCTION(BlueprintPure, Category = "Item|Database")
bool FindContainerDef(FGameplayTag ContainerTag, FContainerDefRow& OutDef) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
bool FindWorldSlotDef(FGameplayTag SlotTag, FWorldSlotDefRow& OutDef) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
bool FindRecipe(FName RecipeId, FCraftingRecipeRow& OutRecipe) const;
UFUNCTION(BlueprintPure, Category = "Item|Database")
void GetAllRecipes(TArray<FCraftingRecipeRow>& OutRecipes) const;
void GetLootEntries(FName TableId, TArray<FLootEntryRow>& Out) const;
/** Rolls a loot table into a list of fresh item instances (server). */
UFUNCTION(BlueprintCallable, Category = "Item|Database")
void RollLoot(FName TableId, int32 RollCount, TArray<FItemInstanceData>& OutItems) const;
// --- Validation (section 28) ---
UFUNCTION(BlueprintCallable, Category = "Item|Database")
void ValidateData(TArray<FItemValidationIssue>& OutIssues) const;
private:
void LoadDefinitions(UDataTable* Table);
void LoadProperties(UDataTable* Table);
void LoadFeatures(UDataTable* Table);
void LoadInteractions(UDataTable* Table);
void LoadRedirects(UDataTable* Table);
void LoadContainers(UDataTable* Table);
void LoadWorldSlots(UDataTable* Table);
void LoadLoot(UDataTable* Table);
void LoadRecipes(UDataTable* Table);
/** ItemId -> definition. */
TMap<FName, FItemDefinitionRow> Definitions;
/** ItemId -> default property rows. */
TMap<FName, TArray<FItemPropertyRow>> PropertiesByItem;
/** ItemId -> feature parameter rows. */
TMap<FName, TArray<FItemFeatureRow>> FeaturesByItem;
/** ItemId -> interaction rows. */
TMap<FName, TArray<FItemInteractionRow>> InteractionsByItem;
/** Old -> new id. */
TMap<FName, FName> Redirects;
TMap<FGameplayTag, FContainerDefRow> ContainerDefs;
TMap<FGameplayTag, FWorldSlotDefRow> WorldSlotDefs;
TMap<FName, TArray<FLootEntryRow>> LootByTable;
TMap<FName, FCraftingRecipeRow> RecipesById;
bool bCacheBuilt = false;
};