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:
85
Source/ItemWorld/Public/EquipmentComponent.h
Normal file
85
Source/ItemWorld/Public/EquipmentComponent.h
Normal file
@ -0,0 +1,85 @@
|
||||
// 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<AActor> 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<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
virtual void OnUnregister() override;
|
||||
|
||||
/** Socket per slot tag; falls back to DefaultEquipSocket. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Equipment")
|
||||
TMap<FGameplayTag, FName> 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<FEquippedItemEntry>& OutEntries) const { OutEntries = Equipped; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(ReplicatedUsing = OnRep_Equipped)
|
||||
TArray<FEquippedItemEntry> Equipped;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_Equipped();
|
||||
|
||||
FName ResolveSocket(const FGameplayTag& SlotTag) const;
|
||||
USceneComponent* GetAttachTarget() const;
|
||||
bool HasAuthority() const;
|
||||
};
|
||||
48
Source/ItemWorld/Public/FuelTankComponent.h
Normal file
48
Source/ItemWorld/Public/FuelTankComponent.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "ItemInteractionInterfaces.h"
|
||||
#include "FuelTankComponent.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnFuelChanged, float, NewFuel);
|
||||
|
||||
/**
|
||||
* A fuel reservoir on a world object (generator, vehicle) that accepts fuel poured
|
||||
* from a held canister (section 15, 31.4). Implements IItemUseTarget for the
|
||||
* "TransferFuel" result verb.
|
||||
*/
|
||||
UCLASS(ClassGroup = (Interaction), meta = (BlueprintSpawnableComponent))
|
||||
class ITEMWORLD_API UFuelTankComponent : public UActorComponent, public IItemUseTarget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFuelTankComponent();
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Fuel")
|
||||
float MaxFuel = 40.f;
|
||||
|
||||
/** Max litres poured per single use action. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Fuel")
|
||||
float PourAmount = 10.f;
|
||||
|
||||
UPROPERTY(ReplicatedUsing = OnRep_Fuel, BlueprintReadOnly, Category = "Fuel")
|
||||
float CurrentFuel = 0.f;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Fuel")
|
||||
FOnFuelChanged OnFuelChanged;
|
||||
|
||||
//~ IItemUseTarget
|
||||
virtual bool ReceiveHeldUse(FName ResultVerb, FItemInstanceData& HeldItem, AActor* Instigator) override;
|
||||
|
||||
protected:
|
||||
UFUNCTION()
|
||||
void OnRep_Fuel();
|
||||
|
||||
bool HasAuthority() const;
|
||||
};
|
||||
151
Source/ItemWorld/Public/HeldItemComponent.h
Normal file
151
Source/ItemWorld/Public/HeldItemComponent.h
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "ItemEnums.h"
|
||||
#include "ItemInstanceData.h"
|
||||
#include "ItemInteractionInterfaces.h"
|
||||
#include "HeldItemComponent.generated.h"
|
||||
|
||||
class APickupItemActor;
|
||||
|
||||
/** Replicated snapshot of what the character is currently holding (section 11.1). */
|
||||
USTRUCT(BlueprintType)
|
||||
struct ITEMWORLD_API FHeldItemState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
bool bHasHeldItem = false;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
FGuid InstanceId;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
FName ItemId;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
EHeldItemMode Mode = EHeldItemMode::None;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
TObjectPtr<AActor> HeldWorldActor = nullptr;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
FName HoldSocket = NAME_None;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
float MoveSpeedMultiplier = 1.f;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
bool bBlocksSprint = false;
|
||||
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
bool bBlocksClimb = false;
|
||||
|
||||
/** Snapshot of the carried item (so we can drop/install it without the actor). */
|
||||
UPROPERTY(BlueprintReadOnly, Category = "Held")
|
||||
FItemInstanceData Item;
|
||||
};
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHeldItemChanged, const FHeldItemState&, NewState);
|
||||
|
||||
/**
|
||||
* Physically carries one bulky item attached to the character (section 11.2-11.3).
|
||||
*
|
||||
* This is the "two-handed carry" path for batteries, canisters, wheels, crates,
|
||||
* corpses, etc. - distinct from equipment (which keeps the item in the inventory
|
||||
* and only spawns a visual). Server-authoritative; visuals/penalties apply on all
|
||||
* clients via OnRep. Implements IHeldItemInterface so the resolver can build
|
||||
* held+target interactions.
|
||||
*/
|
||||
UCLASS(ClassGroup = (Inventory), meta = (BlueprintSpawnableComponent))
|
||||
class ITEMWORLD_API UHeldItemComponent : public UActorComponent, public IHeldItemInterface
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UHeldItemComponent();
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Held")
|
||||
FName CarrySocket = FName("CarrySocket");
|
||||
|
||||
/** Hold distance in front of the view for physics-handle carry (section 11.4). */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Held")
|
||||
float PhysicsHoldDistance = 200.f;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "Held")
|
||||
FOnHeldItemChanged OnHeldItemChanged;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Held")
|
||||
bool HasHeldItemBP() const { return HeldItem.bHasHeldItem; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Held")
|
||||
const FHeldItemState& GetHeldItemState() const { return HeldItem; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Held")
|
||||
bool CanHoldItem(const FItemInstanceData& Item) const;
|
||||
|
||||
/** Client entry: ask the server to drop the carried item (bind to the Drop input). */
|
||||
UFUNCTION(BlueprintCallable, Category = "Held")
|
||||
void RequestDrop();
|
||||
|
||||
// --- Server entry points (section 11.1) ---
|
||||
|
||||
/** Server: pick up and carry a world item actor attached to a socket (World -> Held). */
|
||||
bool ServerHoldWorldItem(AActor* WorldItem);
|
||||
|
||||
/** Server: carry a world item via a physics handle instead of a fixed socket (section 11.4). */
|
||||
bool ServerHoldWorldItemPhysics(AActor* WorldItem);
|
||||
|
||||
/** Server: drop the carried item back into the world (Held -> World). */
|
||||
bool ServerDropHeldItem();
|
||||
|
||||
/** Server: relinquish the carried item without spawning a drop (e.g. on install). */
|
||||
bool ServerConsumeHeldItem(FItemInstanceData& OutItem);
|
||||
|
||||
/**
|
||||
* Server: hand off the carried item AND its actor to a new owner (e.g. a world
|
||||
* slot) without destroying the actor. Clears the held state. Returns false if
|
||||
* nothing was held.
|
||||
*/
|
||||
bool ServerHandOffHeldItem(FItemInstanceData& OutItem, AActor*& OutActor);
|
||||
|
||||
/** Server: update the carried item's data in place (e.g. after pouring out fuel). */
|
||||
bool ServerUpdateHeldItem(const FItemInstanceData& NewItem);
|
||||
|
||||
//~ IHeldItemInterface
|
||||
virtual bool GetHeldItem(FItemInstanceData& OutItem) const override;
|
||||
virtual bool HasHeldItem() const override { return HeldItem.bHasHeldItem; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(ReplicatedUsing = OnRep_HeldItem)
|
||||
FHeldItemState HeldItem;
|
||||
|
||||
UFUNCTION(Server, Reliable)
|
||||
void Server_Drop();
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_HeldItem(FHeldItemState OldState);
|
||||
|
||||
/** Applies/removes the movement-speed penalty on the owning character. */
|
||||
void ApplyMovementState();
|
||||
|
||||
bool HasAuthority() const;
|
||||
|
||||
private:
|
||||
/** Owning character's unmodified MaxWalkSpeed, captured the first time we modify it. */
|
||||
UPROPERTY(Transient)
|
||||
float CachedBaseWalkSpeed = 0.f;
|
||||
|
||||
/** Created on demand for physics-handle carry. */
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<class UPhysicsHandleComponent> PhysicsHandle = nullptr;
|
||||
|
||||
void UpdatePhysicsCarryTarget();
|
||||
};
|
||||
8
Source/ItemWorld/Public/ItemWorldLog.h
Normal file
8
Source/ItemWorld/Public/ItemWorldLog.h
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Logging/LogMacros.h"
|
||||
|
||||
ITEMWORLD_API DECLARE_LOG_CATEGORY_EXTERN(LogItemWorld, Log, All);
|
||||
82
Source/ItemWorld/Public/PickupItemActor.h
Normal file
82
Source/ItemWorld/Public/PickupItemActor.h
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "ItemInstanceData.h"
|
||||
#include "ItemInteractionInterfaces.h"
|
||||
#include "PickupItemActor.generated.h"
|
||||
|
||||
class UStaticMeshComponent;
|
||||
class UInteractableComponent;
|
||||
|
||||
/**
|
||||
* The world representation of an item lying on the ground / a surface (section 12).
|
||||
*
|
||||
* One actor per world item only (never one per inventory item - section 32/34).
|
||||
* Implements IWorldItemProvider so the interaction layer can pick it up, carry it
|
||||
* or take part of its stack without ItemWorld <-> ItemInteraction coupling.
|
||||
*/
|
||||
UCLASS()
|
||||
class ITEMWORLD_API APickupItemActor : public AActor, public IWorldItemProvider
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
APickupItemActor();
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
/** Server: stamp this pickup with an item and refresh its visuals. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Item|World")
|
||||
void InitializeFromItem(const FItemInstanceData& InItem);
|
||||
|
||||
/** Server convenience: spawn a fresh pickup for ItemId at a transform. */
|
||||
UFUNCTION(BlueprintCallable, Category = "Item|World", meta = (WorldContext = "WorldContext"))
|
||||
static APickupItemActor* SpawnPickup(UObject* WorldContext, FName ItemId, int32 Quantity, const FTransform& Transform);
|
||||
|
||||
/** Server convenience: spawn a pickup carrying an existing instance (e.g. on drop). */
|
||||
static APickupItemActor* SpawnPickupFromInstance(UObject* WorldContext, const FItemInstanceData& Item, const FTransform& Transform);
|
||||
|
||||
//~ IWorldItemProvider
|
||||
virtual bool GetProvidedItem(FItemInstanceData& OutItem) const override;
|
||||
virtual bool IsItemAvailable() const override;
|
||||
virtual void NotifyItemTaken(AActor* Taker) override;
|
||||
virtual void UpdateProvidedItem(const FItemInstanceData& RemainingItem) override;
|
||||
virtual void SetCarried(AActor* Holder, bool bCarried) override;
|
||||
|
||||
/** Server: drop this carried actor back into the world at a transform. */
|
||||
void ReleaseToWorld(const FTransform& WorldTransform);
|
||||
|
||||
UStaticMeshComponent* GetMeshComponent() const { return Mesh; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Item|World")
|
||||
const FItemInstanceData& GetItemData() const { return ItemData; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|World")
|
||||
TObjectPtr<USceneComponent> Root;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|World")
|
||||
TObjectPtr<UStaticMeshComponent> Mesh;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item|World")
|
||||
TObjectPtr<UInteractableComponent> Interactable;
|
||||
|
||||
UPROPERTY(ReplicatedUsing = OnRep_ItemData, BlueprintReadOnly, Category = "Item|World")
|
||||
FItemInstanceData ItemData;
|
||||
|
||||
UPROPERTY(Replicated, BlueprintReadOnly, Category = "Item|World")
|
||||
bool bIsLocked = false;
|
||||
|
||||
UPROPERTY(Replicated, BlueprintReadOnly, Category = "Item|World")
|
||||
TObjectPtr<AActor> CurrentHolder = nullptr;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_ItemData();
|
||||
|
||||
/** Resolves the definition and applies WorldMesh + interactable display name. */
|
||||
void RefreshVisuals();
|
||||
};
|
||||
38
Source/ItemWorld/Public/StorageContainerActor.h
Normal file
38
Source/ItemWorld/Public/StorageContainerActor.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "StorageContainerActor.generated.h"
|
||||
|
||||
class UStaticMeshComponent;
|
||||
class UInteractableComponent;
|
||||
class UInventoryComponent;
|
||||
|
||||
/**
|
||||
* A lootable world container (chest, crate, fridge, vehicle cargo, corpse) (section 5).
|
||||
* Its inventory is shared-replicated so any nearby player who opens it sees the
|
||||
* contents; transfers go through the validated server path (section 31.2).
|
||||
*/
|
||||
UCLASS()
|
||||
class ITEMWORLD_API AStorageContainerActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AStorageContainerActor();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Storage")
|
||||
UInventoryComponent* GetStorageInventory() const { return Storage; }
|
||||
|
||||
protected:
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Storage")
|
||||
TObjectPtr<UStaticMeshComponent> Mesh;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Storage")
|
||||
TObjectPtr<UInteractableComponent> Interactable;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Storage")
|
||||
TObjectPtr<UInventoryComponent> Storage;
|
||||
};
|
||||
76
Source/ItemWorld/Public/WorldInteractionActions.h
Normal file
76
Source/ItemWorld/Public/WorldInteractionActions.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "InteractionAction.h"
|
||||
#include "WorldInteractionActions.generated.h"
|
||||
|
||||
/**
|
||||
* World interaction actions (section 16). Each routes through the player's
|
||||
* UItemInteractionComponent::ServerExecuteMode so it shares the one validated
|
||||
* execution path (carry/equip/install/use live in UWorldInteractionComponent).
|
||||
*/
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Carry (Attached)"))
|
||||
class ITEMWORLD_API UInteractionAction_CarryAttached : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_CarryAttached();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Carry (Physics)"))
|
||||
class ITEMWORLD_API UInteractionAction_CarryPhysics : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_CarryPhysics();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Equip"))
|
||||
class ITEMWORLD_API UInteractionAction_Equip : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_Equip();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Drop Held Item"))
|
||||
class ITEMWORLD_API UInteractionAction_DropHeldItem : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_DropHeldItem();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Install Into World Slot"))
|
||||
class ITEMWORLD_API UInteractionAction_InstallIntoWorldSlot : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_InstallIntoWorldSlot();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Remove From World Slot"))
|
||||
class ITEMWORLD_API UInteractionAction_RemoveFromWorldSlot : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_RemoveFromWorldSlot();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
|
||||
UCLASS(meta = (DisplayName = "Action: Use Held On Target"))
|
||||
class ITEMWORLD_API UInteractionAction_UseHeldOnTarget : public UInteractionAction
|
||||
{
|
||||
GENERATED_BODY()
|
||||
public:
|
||||
UInteractionAction_UseHeldOnTarget();
|
||||
virtual void Execute_Implementation(const FInteractionContext& Context) override;
|
||||
};
|
||||
31
Source/ItemWorld/Public/WorldInteractionComponent.h
Normal file
31
Source/ItemWorld/Public/WorldInteractionComponent.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "ItemInteractionComponent.h"
|
||||
#include "WorldInteractionComponent.generated.h"
|
||||
|
||||
/**
|
||||
* The interaction executor to put on a player pawn in a project that uses the
|
||||
* world modules. Extends the base with the modes that need ItemWorld types:
|
||||
* carry, drop-held, equip, install/remove from world slots, and drop-from-inventory
|
||||
* (stages 6-8). Keeps ItemInteraction free of any ItemWorld dependency.
|
||||
*/
|
||||
UCLASS(ClassGroup = (Interaction), meta = (BlueprintSpawnableComponent))
|
||||
class ITEMWORLD_API UWorldInteractionComponent : public UItemInteractionComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
virtual bool ExecuteAuthorized(const FInteractionContext& Context, const FInteractionOption& Option, const FInteractionRequest& Request) override;
|
||||
virtual bool HandleDropFromInventory(FGuid InstanceId) override;
|
||||
|
||||
private:
|
||||
bool ExecuteCarry(const FInteractionContext& Context, bool bPhysics);
|
||||
bool ExecuteDropHeld(const FInteractionContext& Context);
|
||||
bool ExecuteInstall(const FInteractionContext& Context);
|
||||
bool ExecuteEquip(const FInteractionContext& Context, const FInteractionRequest& Request);
|
||||
bool ExecuteUseHeldOnTarget(const FInteractionContext& Context, const FInteractionOption& Option);
|
||||
bool ExecuteRemoveFromSlot(const FInteractionContext& Context);
|
||||
};
|
||||
83
Source/ItemWorld/Public/WorldItemSlotComponent.h
Normal file
83
Source/ItemWorld/Public/WorldItemSlotComponent.h
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "ItemInstanceData.h"
|
||||
#include "WorldItemSlotComponent.generated.h"
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnWorldSlotChanged);
|
||||
|
||||
/** Replicated state of a world slot's contents (section 14). */
|
||||
USTRUCT()
|
||||
struct FWorldSlotInstalledState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY()
|
||||
bool bHasItem = false;
|
||||
|
||||
UPROPERTY()
|
||||
FItemInstanceData Item;
|
||||
};
|
||||
|
||||
/**
|
||||
* A socket on a world object that accepts an installed item (section 14):
|
||||
* Vehicle.Socket.Battery, Generator.Socket.Fuel, Door.Socket.BarricadePlank,
|
||||
* Trap.Socket.Bait, etc. One component per slot.
|
||||
*/
|
||||
UCLASS(ClassGroup = (Interaction), meta = (BlueprintSpawnableComponent))
|
||||
class ITEMWORLD_API UWorldItemSlotComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UWorldItemSlotComponent();
|
||||
|
||||
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
|
||||
|
||||
/** This slot's identity; items list it in CompatibleWorldSlots to fit. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "World Slot")
|
||||
FGameplayTag SlotTag;
|
||||
|
||||
/** Optional extra gate; empty = accept anything whose CompatibleWorldSlots has SlotTag. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "World Slot")
|
||||
FGameplayTagContainer AcceptedItemTags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "World Slot")
|
||||
FName AttachSocketName = NAME_None;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "World Slot")
|
||||
FOnWorldSlotChanged OnSlotChanged;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "World Slot")
|
||||
bool IsOccupied() const { return InstalledItem.bHasItem; }
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "World Slot")
|
||||
bool CanInstall(const FItemInstanceData& Item) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "World Slot")
|
||||
FItemInstanceData GetInstalledItem() const { return InstalledItem.Item; }
|
||||
|
||||
/** Server: install an item. ProvidedVisual (e.g. a carried actor) is reused if given. */
|
||||
bool InstallItem(const FItemInstanceData& Item, AActor* ProvidedVisual = nullptr);
|
||||
|
||||
/** Server: remove and return the installed item. */
|
||||
bool RemoveItem(FItemInstanceData& OutItem);
|
||||
|
||||
protected:
|
||||
UPROPERTY(ReplicatedUsing = OnRep_InstalledItem)
|
||||
FWorldSlotInstalledState InstalledItem;
|
||||
|
||||
/** Server-spawned visual for the installed item (if not provided externally). */
|
||||
UPROPERTY(Replicated)
|
||||
TObjectPtr<AActor> InstalledVisual = nullptr;
|
||||
|
||||
UFUNCTION()
|
||||
void OnRep_InstalledItem();
|
||||
|
||||
USceneComponent* GetAttachTarget() const;
|
||||
bool HasAuthority() const;
|
||||
};
|
||||
Reference in New Issue
Block a user