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:
190
Source/ItemCore/Public/ItemRuntimeProperties.h
Normal file
190
Source/ItemCore/Public/ItemRuntimeProperties.h
Normal file
@ -0,0 +1,190 @@
|
||||
// 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;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user