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>
170 lines
6.1 KiB
C++
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;
|
|
};
|