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:
9
Source/ItemCore/Public/ItemCoreLog.h
Normal file
9
Source/ItemCore/Public/ItemCoreLog.h
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Logging/LogMacros.h"
|
||||
|
||||
/** Shared log categories for the Item Interaction Ecosystem (section 33). */
|
||||
ITEMCORE_API DECLARE_LOG_CATEGORY_EXTERN(LogItemCore, Log, All);
|
||||
19
Source/ItemCore/Public/ItemCoreModule.h
Normal file
19
Source/ItemCore/Public/ItemCoreModule.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
/**
|
||||
* ItemCore module.
|
||||
* Foundation of the Item Interaction Ecosystem: base item structs, ids,
|
||||
* runtime properties, location/state enums and shared log categories.
|
||||
* Contains zero gameplay logic - only data types every other module shares.
|
||||
*/
|
||||
class FItemCoreModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
95
Source/ItemCore/Public/ItemEnums.h
Normal file
95
Source/ItemCore/Public/ItemEnums.h
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ItemEnums.generated.h"
|
||||
|
||||
/**
|
||||
* Where an item instance currently lives (section 5).
|
||||
* Every state transition is validated server-side through the transaction layer.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EItemLocationType : uint8
|
||||
{
|
||||
None,
|
||||
World,
|
||||
Inventory,
|
||||
Container,
|
||||
Held,
|
||||
Equipped,
|
||||
PlacementPreview,
|
||||
Installed,
|
||||
NestedContainer
|
||||
};
|
||||
|
||||
/** Per-property replication scope (section 22). */
|
||||
UENUM(BlueprintType)
|
||||
enum class EItemPropertyReplicationPolicy : uint8
|
||||
{
|
||||
None,
|
||||
OwnerOnly,
|
||||
Everyone,
|
||||
NearbyOnly,
|
||||
ServerOnly
|
||||
};
|
||||
|
||||
/** How an item is currently carried/equipped on a character (section 11). */
|
||||
UENUM(BlueprintType)
|
||||
enum class EHeldItemMode : uint8
|
||||
{
|
||||
None,
|
||||
EquippedFromInventory,
|
||||
CarryAttached,
|
||||
CarryPhysicsHandle,
|
||||
PlacementPreview
|
||||
};
|
||||
|
||||
/** High level interaction mode resolved per option (section 8.5). */
|
||||
UENUM(BlueprintType)
|
||||
enum class EItemInteractionMode : uint8
|
||||
{
|
||||
None,
|
||||
|
||||
InstantPickup,
|
||||
OpenLootUI,
|
||||
PickupToInventory,
|
||||
EquipFromWorld,
|
||||
EquipFromInventory,
|
||||
|
||||
CarryAttached,
|
||||
CarryPhysicsHandle,
|
||||
DropHeldItem,
|
||||
|
||||
Inspect,
|
||||
Use,
|
||||
UseHeldOnTarget,
|
||||
Combine,
|
||||
|
||||
StartPlacement,
|
||||
ConfirmPlacement,
|
||||
CancelPlacement,
|
||||
|
||||
InstallIntoWorldSlot,
|
||||
RemoveFromWorldSlot,
|
||||
|
||||
TransferContainerItem,
|
||||
SplitStack,
|
||||
MergeStack
|
||||
};
|
||||
|
||||
/** Container layout / role (section 7.2). */
|
||||
UENUM(BlueprintType)
|
||||
enum class EInventoryContainerType : uint8
|
||||
{
|
||||
SlotList,
|
||||
Grid,
|
||||
Equipment,
|
||||
Hotbar,
|
||||
VehicleCargo,
|
||||
LootBox,
|
||||
KeyRing,
|
||||
Wallet,
|
||||
CraftingInput,
|
||||
CraftingOutput
|
||||
};
|
||||
92
Source/ItemCore/Public/ItemInstanceData.h
Normal file
92
Source/ItemCore/Public/ItemInstanceData.h
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "ItemEnums.h"
|
||||
#include "ItemRuntimeProperties.h"
|
||||
#include "ItemLockData.h"
|
||||
#include "ItemInstanceData.generated.h"
|
||||
|
||||
/**
|
||||
* Runtime representation of a single item instance (section 4.3).
|
||||
*
|
||||
* Deliberately tiny: it never copies the static FItemDefinitionRow - it only
|
||||
* stores the stable ItemId plus this instance's mutable state. Resolve the
|
||||
* definition through UItemDatabaseSubsystem when you need icons/meshes/flags.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct ITEMCORE_API FItemInstanceData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Globally unique handle for this concrete stack/instance. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
FGuid InstanceId;
|
||||
|
||||
/** Stable design-time id (e.g. "ammo_9mm"). Never a localized string. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
FName ItemId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
int32 Quantity = 1;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
FGameplayTagContainer StateTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
FItemRuntimeProperties RuntimeProperties;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
FGuid CurrentContainerId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
int32 SlotIndex = INDEX_NONE;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
EItemLocationType LocationType = EItemLocationType::None;
|
||||
|
||||
/** Bumped when the item schema changes; drives save migration (section 26.2). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, SaveGame, Category = "Item")
|
||||
int32 ItemDataVersion = 1;
|
||||
|
||||
/** Transient server-side lock; not saved (section 20). */
|
||||
UPROPERTY(BlueprintReadOnly, Transient, Category = "Item")
|
||||
FItemLockData Lock;
|
||||
|
||||
FItemInstanceData() = default;
|
||||
|
||||
explicit FItemInstanceData(FName InItemId, int32 InQuantity = 1)
|
||||
: InstanceId(FGuid::NewGuid())
|
||||
, ItemId(InItemId)
|
||||
, Quantity(InQuantity)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsValid() const { return !ItemId.IsNone() && InstanceId.IsValid() && Quantity > 0; }
|
||||
|
||||
void EnsureInstanceId()
|
||||
{
|
||||
if (!InstanceId.IsValid())
|
||||
{
|
||||
InstanceId = FGuid::NewGuid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Two instances can merge into one stack only when they are the same item,
|
||||
* carry identical per-instance state and neither is locked. MaxStack is
|
||||
* enforced by the inventory layer which has access to the definition.
|
||||
*/
|
||||
bool CanStackWith(const FItemInstanceData& Other) const
|
||||
{
|
||||
return ItemId == Other.ItemId
|
||||
&& !Lock.bLocked && !Other.Lock.bLocked
|
||||
&& StateTags == Other.StateTags
|
||||
&& RuntimeProperties == Other.RuntimeProperties;
|
||||
}
|
||||
|
||||
bool operator==(const FItemInstanceData& Other) const { return InstanceId == Other.InstanceId; }
|
||||
bool operator!=(const FItemInstanceData& Other) const { return InstanceId != Other.InstanceId; }
|
||||
};
|
||||
42
Source/ItemCore/Public/ItemLockData.h
Normal file
42
Source/ItemCore/Public/ItemLockData.h
Normal file
@ -0,0 +1,42 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "ItemLockData.generated.h"
|
||||
|
||||
/**
|
||||
* Server-side soft lock placed on an item while a transaction owns it (section 20).
|
||||
* Prevents dupes / conflicts: a locked item cannot be moved, taken, dropped,
|
||||
* crafted, deleted or stacked by anyone but the locking actor.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct ITEMCORE_API FItemLockData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Item|Lock")
|
||||
bool bLocked = false;
|
||||
|
||||
/** Lock.Carrying / Lock.Using / Lock.Transferring / ... */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Item|Lock")
|
||||
FGameplayTag LockReason;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Item|Lock")
|
||||
TWeakObjectPtr<AActor> LockedBy;
|
||||
|
||||
/** Server world time (seconds) at which the lock auto-expires; 0 = no expiry. */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Item|Lock")
|
||||
float LockExpireTime = 0.f;
|
||||
|
||||
bool IsLockedBy(const AActor* Actor) const { return bLocked && LockedBy.Get() == Actor; }
|
||||
|
||||
void Clear()
|
||||
{
|
||||
bLocked = false;
|
||||
LockReason = FGameplayTag();
|
||||
LockedBy = nullptr;
|
||||
LockExpireTime = 0.f;
|
||||
}
|
||||
};
|
||||
88
Source/ItemCore/Public/ItemNativeTags.h
Normal file
88
Source/ItemCore/Public/ItemNativeTags.h
Normal file
@ -0,0 +1,88 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "NativeGameplayTags.h"
|
||||
|
||||
/**
|
||||
* Native gameplay tags shipped with the framework.
|
||||
*
|
||||
* These cover the built-in behaviour the C++ layer reasons about directly
|
||||
* (lock reasons, the common runtime property tags, the default action verbs).
|
||||
* Project / designer specific tags (item types, world sockets, custom features)
|
||||
* are expected to be declared in the project's tag config or DataTables, not here.
|
||||
*/
|
||||
namespace ItemEcosystemTags
|
||||
{
|
||||
// --- Runtime property tags (section 4.4) ---
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Durability);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Freshness);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_RotProgress);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Temperature);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Wetness);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_FuelAmount);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_MaxFuel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_BatteryCharge);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Contamination);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_NoiseLevel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_SmellIntensity);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_BloodLevel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Radiation);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Poison);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_CookedLevel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_BurnLevel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Quality);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_Charge);
|
||||
/** Server world-time (seconds) of the last lazy feature update (section 21.4). */
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Property_LastUpdateTime);
|
||||
|
||||
// --- State tags (section 4.3 StateTags) ---
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Broken);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Rotten);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Wet);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Contaminated);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(State_Empty);
|
||||
|
||||
// --- Lock reasons (section 20) ---
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Carrying);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Using);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Transferring);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Crafting);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Installing);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Replicating);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Lock_Placement);
|
||||
|
||||
// --- Action verbs (section 6.4 / 8.x) ---
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Pickup_Instant);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Pickup);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Open);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Carry);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Drop);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Equip);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Inspect);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Use);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Install);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Remove);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_Place);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Action_UseHeldOnTarget);
|
||||
|
||||
// --- Feature tags (section 6.3) ---
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Consumable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Rotting);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Durability);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Battery);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Fuel);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Wetness);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Temperature);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_NoiseOnDrop);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Smell);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Container);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Equippable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Throwing);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Breakable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Flammable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Placeable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Installable);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_QuestItem);
|
||||
ITEMCORE_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Feature_Cursed);
|
||||
}
|
||||
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