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:
195
Source/ItemInventory/Public/InventoryComponent.h
Normal file
195
Source/ItemInventory/Public/InventoryComponent.h
Normal file
@ -0,0 +1,195 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "ReplicatedInventoryList.h"
|
||||
#include "InventoryContainer.h"
|
||||
#include "InventoryComponent.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnInventoryChangedSignature);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInventoryItemEventSignature, const FItemInstanceData&, Item);
|
||||
|
||||
/**
|
||||
* Owns and replicates a set of containers full of items (section 7).
|
||||
*
|
||||
* Server-authoritative: every mutating method must run on the server (the
|
||||
* interaction/transaction layer is the only intended caller). Clients receive
|
||||
* state through the FastArray and react via OnInventoryChanged / OnRep. The UI
|
||||
* never mutates this directly (section 25).
|
||||
*/
|
||||
UCLASS(ClassGroup = (Inventory), meta = (BlueprintSpawnableComponent))
|
||||
class ITEMINVENTORY_API UInventoryComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UInventoryComponent();
|
||||
|
||||
//~ UActorComponent
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
virtual void InitializeComponent() override;
|
||||
virtual void OnRegister() override;
|
||||
|
||||
// --- Events (UI binds here, never polls - section 32) ---
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Inventory")
|
||||
FOnInventoryChangedSignature OnInventoryChanged;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Inventory")
|
||||
FOnInventoryItemEventSignature OnItemAdded;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Inventory")
|
||||
FOnInventoryItemEventSignature OnItemRemoved;
|
||||
|
||||
/**
|
||||
* When true (default) inventory replicates only to the owning client (player
|
||||
* inventory, section 25.9). Set false for shared world containers (loot chests,
|
||||
* vehicle cargo) so nearby clients can see the contents. Must be set before the
|
||||
* component registers replication (e.g. in the owning actor's constructor).
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory|Replication")
|
||||
bool bOwnerOnlyReplication = true;
|
||||
|
||||
// --- Container setup ---
|
||||
|
||||
/** Registers a container. Assigns a new ContainerId if unset. Server side. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
FGuid AddContainer(FInventoryContainer Container);
|
||||
|
||||
/** Registers a container from a DT_Containers template (section 6). Server. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
FGuid AddContainerByTag(FGameplayTag ContainerTag);
|
||||
|
||||
/** Creates a nested container owned by an item that has Feature.Container (section 7). */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
FGuid AddNestedContainerForItem(FGuid OwnerItemInstanceId, FGameplayTag ContainerTag);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
bool GetContainer(FGuid ContainerId, FInventoryContainer& OutContainer) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
void GetContainers(TArray<FInventoryContainer>& OutContainers) const { OutContainers = Containers; }
|
||||
|
||||
/** First container whose tag matches, or an invalid guid. */
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
FGuid FindContainerByTag(FGameplayTag ContainerTag) const;
|
||||
|
||||
// --- Core operations (section 7.1) ---
|
||||
|
||||
/** Adds an item, stacking into existing compatible stacks then free slots. Server. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool AddItem(UPARAM(ref) FItemInstanceData& Item);
|
||||
|
||||
/** Adds an item into a specific container. Server. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool AddItemToContainer(UPARAM(ref) FItemInstanceData& Item, FGuid ContainerId);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool RemoveItem(FGuid InstanceId);
|
||||
|
||||
/** Removes up to Amount from a stack; removes the entry when it hits zero. Server. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool RemoveQuantity(FGuid InstanceId, int32 Amount);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool MoveItem(FGuid InstanceId, FGuid FromContainerId, FGuid ToContainerId, int32 TargetSlot);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool SplitStack(FGuid InstanceId, int32 Amount);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool MergeStack(FGuid SourceInstanceId, FGuid TargetInstanceId);
|
||||
|
||||
// --- Queries ---
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
bool CanAcceptItem(const FItemInstanceData& Item, FGuid ContainerId) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
bool FindItem(FGuid InstanceId, FItemInstanceData& OutItem) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
void GetContainerItems(FGuid ContainerId, TArray<FItemInstanceData>& OutItems) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
void GetAllItems(TArray<FItemInstanceData>& OutItems) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
float GetContainerWeight(FGuid ContainerId) const;
|
||||
|
||||
/** Total quantity of a given ItemId across all containers. */
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
int32 GetItemCount(FName ItemId) const;
|
||||
|
||||
// --- Internal mutation used by the transaction layer ---
|
||||
|
||||
/** Writes a mutated copy back into the list and replicates it. Server. */
|
||||
bool UpdateItem(const FItemInstanceData& Item);
|
||||
|
||||
/** Server: place a soft lock on an item so it cannot be moved/taken (section 20). */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool SetItemLock(FGuid InstanceId, FGameplayTag Reason, AActor* LockedBy, float ExpireWorldTime);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
bool ClearItemLock(FGuid InstanceId);
|
||||
|
||||
/** Reads a ServerOnly property kept off the wire (section 22). Server only. */
|
||||
UFUNCTION(BlueprintPure, Category = "Inventory")
|
||||
float GetServerOnlyFloat(FGuid InstanceId, FGameplayTag PropertyTag, float Fallback = 0.f) const;
|
||||
|
||||
/** Direct, unchecked write of an item into a slot (used by transactions). Server. */
|
||||
void SetItemInSlot(const FItemInstanceData& Item, FGuid ContainerId, int32 SlotIndex);
|
||||
|
||||
/** Server: remove every item (save load / debug clear). */
|
||||
UFUNCTION(BlueprintCallable, Category = "Inventory")
|
||||
void ClearAllItems();
|
||||
|
||||
/** Server: replace the container set (save load). */
|
||||
void SetContainers(const TArray<FInventoryContainer>& InContainers);
|
||||
|
||||
/** Broadcasts OnInventoryChanged. Called by the FastArray on clients too. */
|
||||
void NotifyInventoryChanged();
|
||||
void NotifyItemAdded(const FItemInstanceData& Item);
|
||||
void NotifyItemRemoved(const FItemInstanceData& Item);
|
||||
|
||||
protected:
|
||||
UPROPERTY(Replicated)
|
||||
FReplicatedInventoryList ReplicatedItems;
|
||||
|
||||
UPROPERTY(Replicated)
|
||||
TArray<FInventoryContainer> Containers;
|
||||
|
||||
/** Default containers spawned in InitializeComponent (designer-configurable). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Inventory|Setup")
|
||||
TArray<FInventoryContainer> DefaultContainers;
|
||||
|
||||
private:
|
||||
bool HasAuthorityChecked(const TCHAR* Op) const;
|
||||
|
||||
FInventoryContainer* GetContainerMutable(const FGuid& ContainerId);
|
||||
const FInventoryContainer* GetContainerConst(const FGuid& ContainerId) const;
|
||||
|
||||
/** Lowest free slot index in a slot-limited container, or INDEX_NONE if full/unlimited-ok. */
|
||||
int32 FindFreeSlot(const FGuid& ContainerId) const;
|
||||
|
||||
/** Grid-aware free slot for a specific item (uses its GridSize); falls back to FindFreeSlot. */
|
||||
int32 FindFreeSlotForItem(const FGuid& ContainerId, const FItemInstanceData& Item) const;
|
||||
|
||||
FIntPoint GetItemGridSize(FName ItemId) const;
|
||||
|
||||
/** True if the WxH rectangle at TopLeft is inside the grid and unoccupied (ignoring IgnoreInstance). */
|
||||
bool IsGridRegionFree(const FInventoryContainer& Container, int32 TopLeft, FIntPoint Size, const FGuid& IgnoreInstance) const;
|
||||
|
||||
bool IsSlotOccupied(const FGuid& ContainerId, int32 SlotIndex) const;
|
||||
|
||||
/** Tries to top up existing stacks of the same item; reduces Remaining accordingly. */
|
||||
void StackIntoExisting(const FGuid& ContainerId, FItemInstanceData& Item, int32& Remaining);
|
||||
|
||||
/** Moves an item's ServerOnly properties into the server-side side channel (section 22). */
|
||||
void StripServerOnlyProperties(FItemInstanceData& Item);
|
||||
|
||||
/** Server-only properties never replicated to clients, keyed by instance id. */
|
||||
TMap<FGuid, FItemRuntimeProperties> ServerOnlyProps;
|
||||
};
|
||||
Reference in New Issue
Block a user