Files
inventory-system-plugin/Source/ItemCore/Public/ItemRuntimeProperties.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

191 lines
5.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright ExByte Studios. Item Interaction Ecosystem.
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "ItemRuntimeProperties.generated.h"
/**
* Tag->value pairs (section 4.4).
*
* The TЗ sketched these as TMaps, but UHT forbids TMap inside replicated structs,
* and runtime properties must replicate (they live in FItemInstanceData). So they
* are stored as small replicable arrays instead; the typed accessors below hide
* that and behave like a map. N is tiny per item, so linear lookup is fine.
*/
USTRUCT(BlueprintType)
struct FItemFloatProperty
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
FGameplayTag Tag;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
float Value = 0.f;
bool operator==(const FItemFloatProperty& O) const { return Tag == O.Tag && Value == O.Value; }
};
USTRUCT(BlueprintType)
struct FItemIntProperty
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
FGameplayTag Tag;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
int32 Value = 0;
bool operator==(const FItemIntProperty& O) const { return Tag == O.Tag && Value == O.Value; }
};
USTRUCT(BlueprintType)
struct FItemBoolProperty
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
FGameplayTag Tag;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
bool Value = false;
bool operator==(const FItemBoolProperty& O) const { return Tag == O.Tag && Value == O.Value; }
};
USTRUCT(BlueprintType)
struct FItemStringProperty
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
FGameplayTag Tag;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
FString Value;
bool operator==(const FItemStringProperty& O) const { return Tag == O.Tag && Value == O.Value; }
};
/**
* Dynamic, per-instance properties keyed by gameplay tag (section 4.4).
* Only data differing from the definition defaults should be stored, to keep
* replication/save payloads small. Typed accessors fall back when a key is absent.
*/
USTRUCT(BlueprintType)
struct ITEMCORE_API FItemRuntimeProperties
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
TArray<FItemFloatProperty> FloatProperties;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
TArray<FItemIntProperty> IntProperties;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
TArray<FItemBoolProperty> BoolProperties;
UPROPERTY(EditAnywhere, BlueprintReadWrite, SaveGame, Category = "Item|Runtime")
TArray<FItemStringProperty> StringProperties;
bool IsEmpty() const
{
return FloatProperties.Num() == 0 && IntProperties.Num() == 0
&& BoolProperties.Num() == 0 && StringProperties.Num() == 0;
}
// --- Float ---
float GetFloat(const FGameplayTag& Tag, float Fallback = 0.f) const
{
for (const FItemFloatProperty& P : FloatProperties) { if (P.Tag == Tag) { return P.Value; } }
return Fallback;
}
bool HasFloat(const FGameplayTag& Tag) const
{
for (const FItemFloatProperty& P : FloatProperties) { if (P.Tag == Tag) { return true; } }
return false;
}
void SetFloat(const FGameplayTag& Tag, float Value)
{
for (FItemFloatProperty& P : FloatProperties) { if (P.Tag == Tag) { P.Value = Value; return; } }
FloatProperties.Add({ Tag, Value });
}
void RemoveFloat(const FGameplayTag& Tag)
{
FloatProperties.RemoveAll([&Tag](const FItemFloatProperty& P) { return P.Tag == Tag; });
}
// --- Int ---
int32 GetInt(const FGameplayTag& Tag, int32 Fallback = 0) const
{
for (const FItemIntProperty& P : IntProperties) { if (P.Tag == Tag) { return P.Value; } }
return Fallback;
}
bool HasInt(const FGameplayTag& Tag) const
{
for (const FItemIntProperty& P : IntProperties) { if (P.Tag == Tag) { return true; } }
return false;
}
void SetInt(const FGameplayTag& Tag, int32 Value)
{
for (FItemIntProperty& P : IntProperties) { if (P.Tag == Tag) { P.Value = Value; return; } }
IntProperties.Add({ Tag, Value });
}
// --- Bool ---
bool GetBool(const FGameplayTag& Tag, bool Fallback = false) const
{
for (const FItemBoolProperty& P : BoolProperties) { if (P.Tag == Tag) { return P.Value; } }
return Fallback;
}
bool HasBool(const FGameplayTag& Tag) const
{
for (const FItemBoolProperty& P : BoolProperties) { if (P.Tag == Tag) { return true; } }
return false;
}
void SetBool(const FGameplayTag& Tag, bool Value)
{
for (FItemBoolProperty& P : BoolProperties) { if (P.Tag == Tag) { P.Value = Value; return; } }
BoolProperties.Add({ Tag, Value });
}
// --- String ---
FString GetString(const FGameplayTag& Tag, const FString& Fallback = FString()) const
{
for (const FItemStringProperty& P : StringProperties) { if (P.Tag == Tag) { return P.Value; } }
return Fallback;
}
bool HasString(const FGameplayTag& Tag) const
{
for (const FItemStringProperty& P : StringProperties) { if (P.Tag == Tag) { return true; } }
return false;
}
void SetString(const FGameplayTag& Tag, const FString& Value)
{
for (FItemStringProperty& P : StringProperties) { if (P.Tag == Tag) { P.Value = Value; return; } }
StringProperties.Add({ Tag, Value });
}
bool operator==(const FItemRuntimeProperties& Other) const
{
return ArrayEqual(FloatProperties, Other.FloatProperties)
&& ArrayEqual(IntProperties, Other.IntProperties)
&& ArrayEqual(BoolProperties, Other.BoolProperties)
&& ArrayEqual(StringProperties, Other.StringProperties);
}
bool operator!=(const FItemRuntimeProperties& Other) const { return !(*this == Other); }
private:
template<typename T>
static bool ArrayEqual(const TArray<T>& A, const TArray<T>& B)
{
if (A.Num() != B.Num()) { return false; }
for (const T& Elem : A) { if (!B.Contains(Elem)) { return false; } }
return true;
}
};