// Copyright Epic Games, Inc. All Rights Reserved. #include "LyraEquipmentManagerComponent.h" #include "AbilitySystem/LyraAbilitySet.h" #include "AbilitySystem/LyraAbilitySystemComponent.h" #include "AbilitySystemComponent.h" #include "AbilitySystemGlobals.h" #include "Components/ActorComponent.h" #include "Engine/ActorChannel.h" #include "GameFramework/Actor.h" #include "LyraEquipmentDefinition.h" #include "LyraEquipmentInstance.h" #include "Misc/AssertionMacros.h" #include "Net/UnrealNetwork.h" #include "Templates/Casts.h" #include "UObject/Object.h" #include "UObject/ObjectPtr.h" #include "UObject/UObjectBaseUtility.h" class FLifetimeProperty; struct FReplicationFlags; ////////////////////////////////////////////////////////////////////// // FLyraAppliedEquipmentEntry FString FLyraAppliedEquipmentEntry::GetDebugString() const { return FString::Printf(TEXT("%s of %s"), *GetNameSafe(Instance), *GetNameSafe(EquipmentDefinition.Get())); } ////////////////////////////////////////////////////////////////////// // FLyraEquipmentList void FLyraEquipmentList::PreReplicatedRemove(const TArrayView RemovedIndices, int32 FinalSize) { for (int32 Index : RemovedIndices) { const FLyraAppliedEquipmentEntry& Entry = Entries[Index]; if (Entry.Instance != nullptr) { Entry.Instance->OnUnequipped(); } } } void FLyraEquipmentList::PostReplicatedAdd(const TArrayView AddedIndices, int32 FinalSize) { for (int32 Index : AddedIndices) { const FLyraAppliedEquipmentEntry& Entry = Entries[Index]; if (Entry.Instance != nullptr) { Entry.Instance->OnEquipped(); } } } void FLyraEquipmentList::PostReplicatedChange(const TArrayView ChangedIndices, int32 FinalSize) { // for (int32 Index : ChangedIndices) // { // const FGameplayTagStack& Stack = Stacks[Index]; // TagToCountMap[Stack.Tag] = Stack.StackCount; // } } ULyraAbilitySystemComponent* FLyraEquipmentList::GetAbilitySystemComponent() const { check(OwnerComponent); AActor* OwningActor = OwnerComponent->GetOwner(); return Cast(UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(OwningActor)); } ULyraEquipmentInstance* FLyraEquipmentList::AddEntry(TSubclassOf EquipmentDefinition) { ULyraEquipmentInstance* Result = nullptr; check(EquipmentDefinition != nullptr); check(OwnerComponent); check(OwnerComponent->GetOwner()->HasAuthority()); const ULyraEquipmentDefinition* EquipmentCDO = GetDefault(EquipmentDefinition); TSubclassOf InstanceType = EquipmentCDO->InstanceType; if (InstanceType == nullptr) { InstanceType = ULyraEquipmentInstance::StaticClass(); } FLyraAppliedEquipmentEntry& NewEntry = Entries.AddDefaulted_GetRef(); NewEntry.EquipmentDefinition = EquipmentDefinition; NewEntry.Instance = NewObject(OwnerComponent->GetOwner(), InstanceType); //@TODO: Using the actor instead of component as the outer due to UE-127172 Result = NewEntry.Instance; if (ULyraAbilitySystemComponent* ASC = GetAbilitySystemComponent()) { for (TObjectPtr AbilitySet : EquipmentCDO->AbilitySetsToGrant) { AbilitySet->GiveToAbilitySystem(ASC, /*inout*/ &NewEntry.GrantedHandles, Result); } } else { //@TODO: Warning logging? } Result->SpawnEquipmentActors(EquipmentCDO->ActorsToSpawn); MarkItemDirty(NewEntry); return Result; } void FLyraEquipmentList::RemoveEntry(ULyraEquipmentInstance* Instance) { for (auto EntryIt = Entries.CreateIterator(); EntryIt; ++EntryIt) { FLyraAppliedEquipmentEntry& Entry = *EntryIt; if (Entry.Instance == Instance) { if (ULyraAbilitySystemComponent* ASC = GetAbilitySystemComponent()) { Entry.GrantedHandles.TakeFromAbilitySystem(ASC); } Instance->DestroyEquipmentActors(); EntryIt.RemoveCurrent(); MarkArrayDirty(); } } } ////////////////////////////////////////////////////////////////////// // ULyraEquipmentManagerComponent ULyraEquipmentManagerComponent::ULyraEquipmentManagerComponent(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) , EquipmentList(this) { SetIsReplicatedByDefault(true); bWantsInitializeComponent = true; } void ULyraEquipmentManagerComponent::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(ThisClass, EquipmentList); } ULyraEquipmentInstance* ULyraEquipmentManagerComponent::EquipItem(TSubclassOf EquipmentClass) { ULyraEquipmentInstance* Result = nullptr; if (EquipmentClass != nullptr) { Result = EquipmentList.AddEntry(EquipmentClass); if (Result != nullptr) { Result->OnEquipped(); if (IsUsingRegisteredSubObjectList() && IsReadyForReplication()) { AddReplicatedSubObject(Result); } } } return Result; } void ULyraEquipmentManagerComponent::UnequipItem(ULyraEquipmentInstance* ItemInstance) { if (ItemInstance != nullptr) { if (IsUsingRegisteredSubObjectList()) { RemoveReplicatedSubObject(ItemInstance); } ItemInstance->OnUnequipped(); EquipmentList.RemoveEntry(ItemInstance); } } bool ULyraEquipmentManagerComponent::ReplicateSubobjects(UActorChannel* Channel, class FOutBunch* Bunch, FReplicationFlags* RepFlags) { bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags); for (FLyraAppliedEquipmentEntry& Entry : EquipmentList.Entries) { ULyraEquipmentInstance* Instance = Entry.Instance; if (IsValid(Instance)) { WroteSomething |= Channel->ReplicateSubobject(Instance, *Bunch, *RepFlags); } } return WroteSomething; } void ULyraEquipmentManagerComponent::InitializeComponent() { Super::InitializeComponent(); } void ULyraEquipmentManagerComponent::UninitializeComponent() { TArray AllEquipmentInstances; // gathering all instances before removal to avoid side effects affecting the equipment list iterator for (const FLyraAppliedEquipmentEntry& Entry : EquipmentList.Entries) { AllEquipmentInstances.Add(Entry.Instance); } for (ULyraEquipmentInstance* EquipInstance : AllEquipmentInstances) { UnequipItem(EquipInstance); } Super::UninitializeComponent(); } void ULyraEquipmentManagerComponent::ReadyForReplication() { Super::ReadyForReplication(); // Register existing LyraEquipmentInstances if (IsUsingRegisteredSubObjectList()) { for (const FLyraAppliedEquipmentEntry& Entry : EquipmentList.Entries) { ULyraEquipmentInstance* Instance = Entry.Instance; if (IsValid(Instance)) { AddReplicatedSubObject(Instance); } } } } ULyraEquipmentInstance* ULyraEquipmentManagerComponent::GetFirstInstanceOfType(TSubclassOf InstanceType) { for (FLyraAppliedEquipmentEntry& Entry : EquipmentList.Entries) { if (ULyraEquipmentInstance* Instance = Entry.Instance) { if (Instance->IsA(InstanceType)) { return Instance; } } } return nullptr; } TArray ULyraEquipmentManagerComponent::GetEquipmentInstancesOfType(TSubclassOf InstanceType) const { TArray Results; for (const FLyraAppliedEquipmentEntry& Entry : EquipmentList.Entries) { if (ULyraEquipmentInstance* Instance = Entry.Instance) { if (Instance->IsA(InstanceType)) { Results.Add(Instance); } } } return Results; }