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:
129
Source/ItemWorld/Private/WorldItemSlotComponent.cpp
Normal file
129
Source/ItemWorld/Private/WorldItemSlotComponent.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
// Copyright ExByte Studios. Item Interaction Ecosystem.
|
||||
|
||||
#include "WorldItemSlotComponent.h"
|
||||
#include "PickupItemActor.h"
|
||||
#include "ItemWorldLog.h"
|
||||
#include "ItemDatabaseSubsystem.h"
|
||||
#include "ItemDefinitionRow.h"
|
||||
#include "Net/UnrealNetwork.h"
|
||||
|
||||
UWorldItemSlotComponent::UWorldItemSlotComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
SetIsReplicatedByDefault(true);
|
||||
}
|
||||
|
||||
void UWorldItemSlotComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
|
||||
{
|
||||
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
|
||||
DOREPLIFETIME(UWorldItemSlotComponent, InstalledItem);
|
||||
DOREPLIFETIME(UWorldItemSlotComponent, InstalledVisual);
|
||||
}
|
||||
|
||||
bool UWorldItemSlotComponent::HasAuthority() const
|
||||
{
|
||||
return GetOwner() && GetOwner()->HasAuthority();
|
||||
}
|
||||
|
||||
USceneComponent* UWorldItemSlotComponent::GetAttachTarget() const
|
||||
{
|
||||
return GetOwner() ? GetOwner()->GetRootComponent() : nullptr;
|
||||
}
|
||||
|
||||
bool UWorldItemSlotComponent::CanInstall(const FItemInstanceData& Item) const
|
||||
{
|
||||
if (InstalledItem.bHasItem || !Item.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const UItemDatabaseSubsystem* DB = UItemDatabaseSubsystem::Get(this);
|
||||
const FItemDefinitionRow* Def = DB ? DB->GetItemDefinition(Item.ItemId) : nullptr;
|
||||
if (!Def || !Def->bCanInstallIntoWorldSlot)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// The item must declare this slot as compatible.
|
||||
if (!Def->CompatibleWorldSlots.HasTag(SlotTag))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Optional extra tag gate.
|
||||
if (!AcceptedItemTags.IsEmpty())
|
||||
{
|
||||
FGameplayTagContainer ItemTags = Def->ItemTags;
|
||||
ItemTags.AddTag(Def->ItemType);
|
||||
if (!ItemTags.HasAny(AcceptedItemTags))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UWorldItemSlotComponent::InstallItem(const FItemInstanceData& Item, AActor* ProvidedVisual)
|
||||
{
|
||||
if (!HasAuthority() || !CanInstall(Item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
InstalledItem.bHasItem = true;
|
||||
InstalledItem.Item = Item;
|
||||
InstalledItem.Item.LocationType = EItemLocationType::Installed;
|
||||
|
||||
if (ProvidedVisual)
|
||||
{
|
||||
// Reuse the carried actor as the visual.
|
||||
if (USceneComponent* Target = GetAttachTarget())
|
||||
{
|
||||
ProvidedVisual->AttachToComponent(Target, FAttachmentTransformRules::SnapToTargetIncludingScale, AttachSocketName);
|
||||
}
|
||||
if (IWorldItemProvider* Provider = Cast<IWorldItemProvider>(ProvidedVisual))
|
||||
{
|
||||
Provider->SetCarried(GetOwner(), true); // keep collision off, locked
|
||||
}
|
||||
InstalledVisual = ProvidedVisual;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Spawn a fresh visual pickup and attach it.
|
||||
const FTransform Xf = GetAttachTarget() ? GetAttachTarget()->GetComponentTransform() : GetOwner()->GetActorTransform();
|
||||
if (APickupItemActor* Visual = APickupItemActor::SpawnPickupFromInstance(this, Item, Xf))
|
||||
{
|
||||
Visual->SetCarried(GetOwner(), true);
|
||||
if (USceneComponent* Target = GetAttachTarget())
|
||||
{
|
||||
Visual->AttachToComponent(Target, FAttachmentTransformRules::SnapToTargetIncludingScale, AttachSocketName);
|
||||
}
|
||||
InstalledVisual = Visual;
|
||||
}
|
||||
}
|
||||
|
||||
OnSlotChanged.Broadcast();
|
||||
UE_LOG(LogItemWorld, Log, TEXT("[Interaction] installed %s into %s"), *Item.ItemId.ToString(), *SlotTag.ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UWorldItemSlotComponent::RemoveItem(FItemInstanceData& OutItem)
|
||||
{
|
||||
if (!HasAuthority() || !InstalledItem.bHasItem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
OutItem = InstalledItem.Item;
|
||||
|
||||
if (InstalledVisual)
|
||||
{
|
||||
InstalledVisual->Destroy();
|
||||
InstalledVisual = nullptr;
|
||||
}
|
||||
|
||||
InstalledItem = FWorldSlotInstalledState();
|
||||
OnSlotChanged.Broadcast();
|
||||
return true;
|
||||
}
|
||||
|
||||
void UWorldItemSlotComponent::OnRep_InstalledItem()
|
||||
{
|
||||
OnSlotChanged.Broadcast();
|
||||
}
|
||||
Reference in New Issue
Block a user