// Copyright ExByte Studios. Item Interaction Ecosystem. #pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "GameplayTagContainer.h" #include "ItemInstanceData.h" #include "EquipmentComponent.generated.h" /** * One equipped slot (section 11.2 Equipped). The item itself stays in the * inventory; only the visual actor is spawned and replicated. */ USTRUCT(BlueprintType) struct FEquippedItemEntry { GENERATED_BODY() UPROPERTY(BlueprintReadOnly, Category = "Equipment") FGameplayTag SlotTag; UPROPERTY(BlueprintReadOnly, Category = "Equipment") FGuid InstanceId; UPROPERTY(BlueprintReadOnly, Category = "Equipment") FName ItemId; UPROPERTY(BlueprintReadOnly, Category = "Equipment") TObjectPtr EquippedActor = nullptr; }; DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnEquipmentChanged); /** * Spawns/attaches the visual actors for equipped items (section 7, 11.2, 31.5). * * Equip keeps the item in the inventory and only manages the EquippedActorClass * visual - distinct from carry (UHeldItemComponent), which physically removes the * item from storage. Owner-only item truth, everyone sees the visual (section 22/25). */ UCLASS(ClassGroup = (Inventory), meta = (BlueprintSpawnableComponent)) class ITEMWORLD_API UEquipmentComponent : public UActorComponent { GENERATED_BODY() public: UEquipmentComponent(); virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual void OnUnregister() override; /** Socket per slot tag; falls back to DefaultEquipSocket. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Equipment") TMap SlotSockets; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Equipment") FName DefaultEquipSocket = FName("hand_rSocket"); UPROPERTY(BlueprintAssignable, Category = "Equipment") FOnEquipmentChanged OnEquipmentChanged; /** Server: equip an inventory item into a slot (Inventory -> Equipped). */ bool ServerEquip(FGuid InstanceId, FGameplayTag SlotTag); /** Server: remove the equipped visual from a slot. */ bool ServerUnequip(FGameplayTag SlotTag); UFUNCTION(BlueprintPure, Category = "Equipment") bool IsSlotEquipped(FGameplayTag SlotTag) const; UFUNCTION(BlueprintPure, Category = "Equipment") void GetEquippedEntries(TArray& OutEntries) const { OutEntries = Equipped; } protected: UPROPERTY(ReplicatedUsing = OnRep_Equipped) TArray Equipped; UFUNCTION() void OnRep_Equipped(); FName ResolveSocket(const FGameplayTag& SlotTag) const; USceneComponent* GetAttachTarget() const; bool HasAuthority() const; };