FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::SetStackCountToMax(FGameplayEffectSpecHandle SpecHandle) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec && Spec->Def) { Spec->StackCount = Spec->Def->StackLimitCount; } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AddLinkedGameplayEffectSpec called with invalid SpecHandle")); } return SpecHandle; }
bool UGameplayAbility::ShouldAbilityRespondToEvent(FGameplayTag EventTag, const FGameplayEventData* Payload) const { if (HasBlueprintShouldAbilityRespondToEvent) { if (K2_ShouldAbilityRespondToEvent(*Payload) == false) { ABILITY_LOG(Log, TEXT("ShouldAbilityRespondToEvent %s failed, blueprint refused"), *GetName()); return false; } } return true; }
bool FGameplayEffectContextHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { UScriptStruct* ScriptStruct = Data.IsValid() ? Data->GetScriptStruct() : NULL; Ar << ScriptStruct; if (ScriptStruct) { if (Ar.IsLoading()) { // For now, just always reset/reallocate the data when loading. // Longer term if we want to generalize this and use it for property replication, we should support // only reallocating when necessary check(!Data.IsValid()); FGameplayEffectContext * NewData = (FGameplayEffectContext*)FMemory::Malloc(ScriptStruct->GetCppStructOps()->GetSize()); ScriptStruct->InitializeStruct(NewData); Data = TSharedPtr<FGameplayEffectContext>(NewData); } void* ContainerPtr = Data.Get(); if (ScriptStruct->StructFlags & STRUCT_NetSerializeNative) { ScriptStruct->GetCppStructOps()->NetSerialize(Ar, Map, bOutSuccess, Data.Get()); } else { // This won't work since UStructProperty::NetSerializeItem is deprecrated. // 1) we have to manually crawl through the topmost struct's fields since we don't have a UStructProperty for it (just the UScriptProperty) // 2) if there are any UStructProperties in the topmost struct's fields, we will assert in UStructProperty::NetSerializeItem. ABILITY_LOG(Fatal, TEXT("FGameplayEffectContextHandle::NetSerialize called on data struct %s without a native NetSerialize"), *ScriptStruct->GetName()); for (TFieldIterator<UProperty> It(ScriptStruct); It; ++It) { if (It->PropertyFlags & CPF_RepSkip) { continue; } void * PropertyData = It->ContainerPtrToValuePtr<void*>(ContainerPtr); It->NetSerializeItem(Ar, Map, PropertyData); } } } bOutSuccess = true; return true; }
FGameplayEffectContextHandle UAbilitySystemBlueprintLibrary::GetEffectContext(FGameplayEffectSpecHandle SpecHandle) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { return Spec->GetEffectContext(); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::GetEffectContext called with invalid SpecHandle")); } return FGameplayEffectContextHandle(); }
void UAbilityTask_ApplyRootMotionMoveToActorForce::SharedInitAndApply() { if (AbilitySystemComponent->AbilityActorInfo->MovementComponent.IsValid()) { MovementComponent = Cast<UCharacterMovementComponent>(AbilitySystemComponent->AbilityActorInfo->MovementComponent.Get()); StartTime = GetWorld()->GetTimeSeconds(); EndTime = StartTime + Duration; if (MovementComponent) { if (bSetNewMovementMode) { PreviousMovementMode = MovementComponent->MovementMode; MovementComponent->SetMovementMode(NewMovementMode); } // Set initial target location if (TargetActor) { TargetLocation = CalculateTargetOffset(); } ForceName = ForceName.IsNone() ? FName("AbilityTaskApplyRootMotionMoveToActorForce") : ForceName; FRootMotionSource_MoveToDynamicForce* MoveToActorForce = new FRootMotionSource_MoveToDynamicForce(); MoveToActorForce->InstanceName = ForceName; MoveToActorForce->AccumulateMode = ERootMotionAccumulateMode::Override; MoveToActorForce->Settings.SetFlag(ERootMotionSourceSettingsFlags::UseSensitiveLiftoffCheck); MoveToActorForce->Priority = 900; MoveToActorForce->InitialTargetLocation = TargetLocation; MoveToActorForce->TargetLocation = TargetLocation; MoveToActorForce->StartLocation = StartLocation; MoveToActorForce->Duration = Duration; MoveToActorForce->bRestrictSpeedToExpected = bRestrictSpeedToExpected; MoveToActorForce->PathOffsetCurve = PathOffsetCurve; MoveToActorForce->TimeMappingCurve = TimeMappingCurve; RootMotionSourceID = MovementComponent->ApplyRootMotionSource(MoveToActorForce); if (Ability) { Ability->SetMovementSyncPoint(ForceName); } } } else { ABILITY_LOG(Warning, TEXT("UAbilityTask_ApplyRootMotionMoveToActorForce called in Ability %s with null MovementComponent; Task Instance Name %s."), Ability ? *Ability->GetName() : TEXT("NULL"), *InstanceName.ToString()); } }
FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AssignSetByCallerMagnitude(FGameplayEffectSpecHandle SpecHandle, FName DataName, float Magnitude) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { Spec->SetSetByCallerMagnitude(DataName, Magnitude); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AssignSetByCallerMagnitude called with invalid SpecHandle")); } return SpecHandle; }
FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::SetDuration(FGameplayEffectSpecHandle SpecHandle, float Duration) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { Spec->SetDuration(Duration, true); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::SetDuration called with invalid SpecHandle")); } return SpecHandle; }
FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AddAssetTags(FGameplayEffectSpecHandle SpecHandle, FGameplayTagContainer NewGameplayTags) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { Spec->DynamicAssetTags.AppendTags(NewGameplayTags); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AddEffectTags called with invalid SpecHandle")); } return SpecHandle; }
FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AddGrantedTag(FGameplayEffectSpecHandle SpecHandle, FGameplayTag NewGameplayTag) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { Spec->DynamicGrantedTags.AddTag(NewGameplayTag); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AddGrantedTag called with invalid SpecHandle")); } return SpecHandle; }
FGameplayEffectSpecHandle UAbilitySystemBlueprintLibrary::AddLinkedGameplayEffectSpec(FGameplayEffectSpecHandle SpecHandle, FGameplayEffectSpecHandle LinkedGameplayEffectSpec) { FGameplayEffectSpec* Spec = SpecHandle.Data.Get(); if (Spec) { Spec->TargetEffectSpecs.Add(LinkedGameplayEffectSpec); } else { ABILITY_LOG(Warning, TEXT("UAbilitySystemBlueprintLibrary::AddLinkedGameplayEffectSpec called with invalid SpecHandle")); } return SpecHandle; }
bool UGameplayAbility::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const { SetCurrentActorInfo(Handle, ActorInfo); if (ActorInfo->AbilitySystemComponent->GetUserAbilityActivationInhibited()) { /** * Input is inhibited (UI is pulled up, another ability may be blocking all other input, etc). * When we get into triggered abilities, we may need to better differentiate between CanActviate and CanUserActivate or something. * E.g., we would want LMB/RMB to be inhibited while the user is in the menu UI, but we wouldn't want to prevent a 'buff when I am low health' * ability to not trigger. * * Basically: CanActivateAbility is only used by user activated abilities now. If triggered abilities need to check costs/cooldowns, then we may * want to split this function up and change the calling API to distinguish between 'can I initiate an ability activation' and 'can this ability be activated'. */ return false; } if (!CheckCooldown(ActorInfo)) { return false; } if (!CheckCost(ActorInfo)) { return false; } // If we're instance per actor and we already have an instance, don't let us activate again as this breaks the graph if (GetInstancingPolicy() == EGameplayAbilityInstancingPolicy::InstancedPerActor) { if (bIsActive) { return false; } } if (HasBlueprintCanUse) { if (K2_CanActivateAbility(*ActorInfo) == false) { ABILITY_LOG(Log, TEXT("CanActivateAbility %s failed, blueprint refused"), *GetName()); return false; } } return true; }
/** Outside code is saying 'stop everything and just forget about it' */ void AGameplayAbilityTargetActor::CancelTargeting() { const FGameplayAbilityActorInfo* ActorInfo = (OwningAbility ? OwningAbility->GetCurrentActorInfo() : nullptr); UAbilitySystemComponent* ASC = (ActorInfo ? ActorInfo->AbilitySystemComponent.Get() : nullptr); if (ASC) { ASC->AbilityReplicatedEventDelegate(EAbilityGenericReplicatedEvent::GenericCancel, OwningAbility->GetCurrentAbilitySpecHandle(), OwningAbility->GetCurrentActivationInfo().GetActivationPredictionKey() ).Remove(GenericCancelHandle); } else { ABILITY_LOG(Warning, TEXT("AGameplayAbilityTargetActor::CancelTargeting called with null ASC! Actor %s"), *GetName()); } CanceledDelegate.Broadcast(FGameplayAbilityTargetDataHandle()); Destroy(); }
void UGameplayCueManager::CheckForTooManyRPCs(FName FuncName, const FGameplayCuePendingExecute& PendingCue, const FString& CueID, const FGameplayEffectContext* EffectContext) { if (GameplayCueCheckForTooManyRPCs) { static IConsoleVariable* MaxRPCPerNetUpdateCVar = IConsoleManager::Get().FindConsoleVariable(TEXT("net.MaxRPCPerNetUpdate")); if (MaxRPCPerNetUpdateCVar) { AActor* Owner = PendingCue.OwningComponent ? PendingCue.OwningComponent->GetOwner() : nullptr; UWorld* World = Owner ? Owner->GetWorld() : nullptr; UNetDriver* NetDriver = World ? World->GetNetDriver() : nullptr; if (NetDriver) { const int32 MaxRPCs = MaxRPCPerNetUpdateCVar->GetInt(); for (UNetConnection* ClientConnection : NetDriver->ClientConnections) { if (ClientConnection) { UActorChannel** OwningActorChannelPtr = ClientConnection->ActorChannels.Find(Owner); TSharedRef<FObjectReplicator>* ComponentReplicatorPtr = (OwningActorChannelPtr && *OwningActorChannelPtr) ? (*OwningActorChannelPtr)->ReplicationMap.Find(PendingCue.OwningComponent) : nullptr; if (ComponentReplicatorPtr) { const TArray<FObjectReplicator::FRPCCallInfo>& RemoteFuncInfo = (*ComponentReplicatorPtr)->RemoteFuncInfo; for (const FObjectReplicator::FRPCCallInfo& CallInfo : RemoteFuncInfo) { if (CallInfo.FuncName == FuncName) { if (CallInfo.Calls > MaxRPCs) { const FString Instigator = EffectContext ? EffectContext->ToString() : TEXT("None"); ABILITY_LOG(Warning, TEXT("Attempted to fire %s when no more RPCs are allowed this net update. Max:%d Cue:%s Instigator:%s Component:%s"), *FuncName.ToString(), MaxRPCs, *CueID, *Instigator, *GetPathNameSafe(PendingCue.OwningComponent)); // Returning here to only log once per offending RPC. return; } break; } } } } } } } } }
void UGameplayCueNotify_HitImpact::HandleGameplayCue(AActor* Self, EGameplayCueEvent::Type EventType, FGameplayCueParameters Parameters) { check(EventType == EGameplayCueEvent::Executed); check(Self); const FHitResult* HitResult = Parameters.EffectContext.GetHitResult(); if (HitResult) { if (ParticleSystem) { UGameplayStatics::SpawnEmitterAtLocation(Self, ParticleSystem, HitResult->ImpactPoint, HitResult->ImpactNormal.Rotation(), true); } } else { ABILITY_LOG(Warning, TEXT("GameplayCue %s was called on GameplayCueNotify but there was no HitResult to spawn an impact from."), *Parameters.MatchedTagName.ToString(), *GetName() ); } }
void UGameplayCueManager::InvokeGameplayCueAddedAndWhileActive_FromSpec(UAbilitySystemComponent* OwningComponent, const FGameplayEffectSpec& Spec, FPredictionKey PredictionKey) { if (Spec.Def->GameplayCues.Num() == 0) { return; } if (AbilitySystemAlwaysConvertGESpecToGCParams) { // Transform the GE Spec into GameplayCue parmameters here (on the server) FGameplayCueParameters Parameters; UAbilitySystemGlobals::Get().InitGameplayCueParameters_GESpec(Parameters, Spec); static TArray<FGameplayTag, TInlineAllocator<4> > Tags; Tags.Reset(); PullGameplayCueTagsFromSpec(Spec, Tags); if (Tags.Num() == 1) { OwningComponent->NetMulticast_InvokeGameplayCueAddedAndWhileActive_WithParams(Tags[0], PredictionKey, Parameters); } else if (Tags.Num() > 1) { OwningComponent->NetMulticast_InvokeGameplayCuesAddedAndWhileActive_WithParams(FGameplayTagContainer::CreateFromArray(Tags), PredictionKey, Parameters); } else { ABILITY_LOG(Warning, TEXT("No actual gameplay cue tags found in GameplayEffect %s (despite it having entries in its gameplay cue list!"), *Spec.Def->GetName()); } } else { OwningComponent->NetMulticast_InvokeGameplayCueAddedAndWhileActive_FromSpec(Spec, PredictionKey); } }
float FScalableFloat::GetValueAtLevel(float Level) const { if (Curve.CurveTable != nullptr) { if (FinalCurve == nullptr) { static const FString ContextString = TEXT("FScalableFloat::FinalizeCurveData"); FinalCurve = Curve.GetCurve(ContextString); } if (FinalCurve != nullptr) { return Value * FinalCurve->Eval(Level); } else { ABILITY_LOG(Error, TEXT("Unable to find RowName: %s for FScalableFloat."), *Curve.RowName.ToString()); } } return Value; }
bool FGameplayEffectContextHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { bool ValidData = Data.IsValid(); Ar.SerializeBits(&ValidData,1); if (ValidData) { if (Ar.IsLoading()) { // For now, just always reset/reallocate the data when loading. // Longer term if we want to generalize this and use it for property replication, we should support // only reallocating when necessary if (Data.IsValid() == false) { Data = TSharedPtr<FGameplayEffectContext>(UAbilitySystemGlobals::Get().AllocGameplayEffectContext()); } } void* ContainerPtr = Data.Get(); UScriptStruct* ScriptStruct = Data->GetScriptStruct(); if (ScriptStruct->StructFlags & STRUCT_NetSerializeNative) { ScriptStruct->GetCppStructOps()->NetSerialize(Ar, Map, bOutSuccess, Data.Get()); } else { // This won't work since UStructProperty::NetSerializeItem is deprecrated. // 1) we have to manually crawl through the topmost struct's fields since we don't have a UStructProperty for it (just the UScriptProperty) // 2) if there are any UStructProperties in the topmost struct's fields, we will assert in UStructProperty::NetSerializeItem. ABILITY_LOG(Fatal, TEXT("FGameplayEffectContextHandle::NetSerialize called on data struct %s without a native NetSerialize"), *ScriptStruct->GetName()); } } bOutSuccess = true; return true; }
float FAggregator::EvaluateWithBase(float InlineBaseValue, const FAggregatorEvaluateParameters& Parameters) const { for (const FAggregatorMod& Mod : Mods[EGameplayModOp::Override]) { if (Mod.Qualifies(Parameters)) { return Mod.EvaluatedMagnitude; } } float Additive = SumMods(Mods[EGameplayModOp::Additive], GameplayEffectUtilities::GetModifierBiasByModifierOp(EGameplayModOp::Additive), Parameters); float Multiplicitive = SumMods(Mods[EGameplayModOp::Multiplicitive], GameplayEffectUtilities::GetModifierBiasByModifierOp(EGameplayModOp::Multiplicitive), Parameters); float Division = SumMods(Mods[EGameplayModOp::Division], GameplayEffectUtilities::GetModifierBiasByModifierOp(EGameplayModOp::Division), Parameters); if (FMath::IsNearlyZero(Division)) { ABILITY_LOG(Warning, TEXT("Division summation was 0.0f in FAggregator.")); Division = 1.f; } return ((InlineBaseValue + Additive) * Multiplicitive) / Division; }
void AGameplayAbilityTargetActor::ConfirmTargeting() { const FGameplayAbilityActorInfo* ActorInfo = (OwningAbility ? OwningAbility->GetCurrentActorInfo() : nullptr); UAbilitySystemComponent* ASC = (ActorInfo ? ActorInfo->AbilitySystemComponent.Get() : nullptr); if (ASC) { ASC->AbilityReplicatedEventDelegate(EAbilityGenericReplicatedEvent::GenericConfirm, OwningAbility->GetCurrentAbilitySpecHandle(), OwningAbility->GetCurrentActivationInfo().GetActivationPredictionKey() ).Remove(GenericConfirmHandle); } else { ABILITY_LOG(Warning, TEXT("AGameplayAbilityTargetActor::ConfirmTargeting called with null Ability/ASC! Actor %s"), *GetName()); } if (IsConfirmTargetingAllowed()) { ConfirmTargetingAndContinue(); if (bDestroyOnConfirmation) { Destroy(); } } }
void UAbilityTask_ApplyRootMotionJumpForce::SharedInitAndApply() { if (AbilitySystemComponent->AbilityActorInfo->MovementComponent.IsValid()) { MovementComponent = Cast<UCharacterMovementComponent>(AbilitySystemComponent->AbilityActorInfo->MovementComponent.Get()); StartTime = GetWorld()->GetTimeSeconds(); EndTime = StartTime + Duration; if (MovementComponent) { ForceName = ForceName.IsNone() ? FName("AbilityTaskApplyRootMotionJumpForce") : ForceName; FRootMotionSource_JumpForce* JumpForce = new FRootMotionSource_JumpForce(); JumpForce->InstanceName = ForceName; JumpForce->AccumulateMode = ERootMotionAccumulateMode::Override; JumpForce->Priority = 500; JumpForce->Duration = Duration; JumpForce->Rotation = Rotation; JumpForce->Distance = Distance; JumpForce->Height = Height; JumpForce->Duration = Duration; JumpForce->bDisableTimeout = bFinishOnLanded; // If we finish on landed, we need to disable force's timeout JumpForce->PathOffsetCurve = PathOffsetCurve; JumpForce->TimeMappingCurve = TimeMappingCurve; RootMotionSourceID = MovementComponent->ApplyRootMotionSource(JumpForce); if (Ability) { Ability->SetMovementSyncPoint(ForceName); } } } else { ABILITY_LOG(Warning, TEXT("UAbilityTask_ApplyRootMotionJumpForce called in Ability %s with null MovementComponent; Task Instance Name %s."), Ability ? *Ability->GetName() : TEXT("NULL"), *InstanceName.ToString()); } }
void UGameplayCueManager::DumpPreallocationStats(UWorld* World) { if (World == nullptr) { return; } FPreallocationInfo& Info = GetPreallocationInfo(World); for (auto &It : Info.PreallocatedInstances) { if (UClass* ThisClass = It.Key) { if (AGameplayCueNotify_Actor* CDO = ThisClass->GetDefaultObject<AGameplayCueNotify_Actor>()) { TArray<AGameplayCueNotify_Actor*>& List = It.Value; if (List.Num() > CDO->NumPreallocatedInstances) { ABILITY_LOG(Display, TEXT("Notify class: %s was used simultaneously %d times. The CDO default is %d preallocated instanced."), *ThisClass->GetName(), List.Num(), CDO->NumPreallocatedInstances); } } } } }
/** * Transforms CurveTable data into format more effecient to read at runtime. * UCurveTable requires string parsing to map to GroupName/AttributeSet/Attribute * Each curve in the table represents a *single attribute's values for all levels*. * At runtime, we want *all attribute values at given level*. */ void FAttributeSetInitter::PreloadAttributeSetData(UCurveTable* CurveData) { if(!ensure(CurveData)) { return; } /** * Get list of AttributeSet classes loaded */ TArray<TSubclassOf<UAttributeSet> > ClassList; for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* TestClass = *ClassIt; if (TestClass->IsChildOf(UAttributeSet::StaticClass())) { ClassList.Add(TestClass); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // This can only work right now on POD attribute sets. If we ever support FStrings or TArrays in AttributeSets // we will need to update this code to not use memcpy etc. for (TFieldIterator<UProperty> PropIt(TestClass, EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt) { if (!PropIt->HasAllPropertyFlags(CPF_IsPlainOldData)) { ABILITY_LOG(Error, TEXT("FAttributeSetInitter::PreloadAttributeSetData Unable to Handle AttributeClass %s because it has a non POD property: %s"), *TestClass->GetName(), *PropIt->GetName()); return; } } #endif } } /** * Loop through CurveData table and build sets of Defaults that keyed off of Name + Level */ for (auto It = CurveData->RowMap.CreateConstIterator(); It; ++It) { FString RowName = It.Key().ToString(); FString ClassName; FString SetName; FString AttributeName; FString Temp; RowName.Split(TEXT("."), &ClassName, &Temp); Temp.Split(TEXT("."), &SetName, &AttributeName); if (!ensure(!ClassName.IsEmpty() && !SetName.IsEmpty() && !AttributeName.IsEmpty())) { ABILITY_LOG(Verbose, TEXT("FAttributeSetInitter::PreloadAttributeSetData Unable to parse row %s in %s"), *RowName, *CurveData->GetName()); continue; } // Find the AttributeSet TSubclassOf<UAttributeSet> Set = FindBestAttributeClass(ClassList, SetName); if (!Set) { // This is ok, we may have rows in here that don't correspond directly to attributes ABILITY_LOG(Verbose, TEXT("FAttributeSetInitter::PreloadAttributeSetData Unable to match AttributeSet from %s (row: %s)"), *SetName, *RowName); continue; } // Find the UProperty UNumericProperty* Property = FindField<UNumericProperty>(*Set, *AttributeName); if (!Property) { ABILITY_LOG(Verbose, TEXT("FAttributeSetInitter::PreloadAttributeSetData Unable to match Attribute from %s (row: %s)"), *AttributeName, *RowName); continue; } FRichCurve* Curve = It.Value(); FName ClassFName = FName(*ClassName); FAttributeSetDefaulsCollection& DefaultCollection = Defaults.FindOrAdd(ClassFName); int32 LastLevel = Curve->GetLastKey().Time; DefaultCollection.LevelData.SetNum(FMath::Max(LastLevel, DefaultCollection.LevelData.Num())); //At this point we know the Name of this "class"/"group", the AttributeSet, and the Property Name. Now loop through the values on the curve to get the attribute default value at each level. for (auto KeyIter = Curve->GetKeyIterator(); KeyIter; ++KeyIter) { const FRichCurveKey& CurveKey = *KeyIter; int32 Level = CurveKey.Time; float Value = CurveKey.Value; FAttributeSetDefaults& SetDefaults = DefaultCollection.LevelData[Level-1]; FAttributeDefaultValueList* DefaultDataList = SetDefaults.DataMap.Find(Set); if (DefaultDataList == nullptr) { ABILITY_LOG(Verbose, TEXT("Initializing new default set for %s[%d]. PropertySize: %d.. DefaultSize: %d"), *Set->GetName(), Level, Set->GetPropertiesSize(), UAttributeSet::StaticClass()->GetPropertiesSize()); DefaultDataList = &SetDefaults.DataMap.Add(Set); } // Import curve value into default data check(DefaultDataList); DefaultDataList->AddPair(Property, Value); } } }
bool FGameplayAbilityTargetDataHandle::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess) { uint8 DataNum; if (Ar.IsSaving()) { UE_CLOG(Data.Num() > MAX_uint8, LogAbilitySystem, Warning, TEXT("Too many TargetData sources (%d!) to net serialize. Clamping to %d"), Data.Num(), MAX_uint8); DataNum = FMath::Min<int32>( Data.Num(), MAX_uint8 ); } Ar << DataNum; if (Ar.IsLoading()) { Data.SetNumZeroed(DataNum); } for (int32 i = 0; i < DataNum && !Ar.IsError(); ++i) { UScriptStruct* ScriptStruct = Data[i].IsValid() ? Data[i]->GetScriptStruct() : NULL; Ar << ScriptStruct; if (ScriptStruct) { if (Ar.IsLoading()) { // For now, just always reset/reallocate the data when loading. // Longer term if we want to generalize this and use it for property replication, we should support // only reallocating when necessary check(!Data[i].IsValid()); FGameplayAbilityTargetData * NewData = (FGameplayAbilityTargetData*)FMemory::Malloc(ScriptStruct->GetCppStructOps()->GetSize()); ScriptStruct->InitializeStruct(NewData); Data[i] = TSharedPtr<FGameplayAbilityTargetData>(NewData); } void* ContainerPtr = Data[i].Get(); if (ScriptStruct->StructFlags & STRUCT_NetSerializeNative) { ScriptStruct->GetCppStructOps()->NetSerialize(Ar, Map, bOutSuccess, Data[i].Get()); } else { // This won't work since UStructProperty::NetSerializeItem is deprecrated. // 1) we have to manually crawl through the topmost struct's fields since we don't have a UStructProperty for it (just the UScriptProperty) // 2) if there are any UStructProperties in the topmost struct's fields, we will assert in UStructProperty::NetSerializeItem. ABILITY_LOG(Fatal, TEXT("FGameplayAbilityTargetDataHandle::NetSerialize called on data struct %s without a native NetSerialize"), *ScriptStruct->GetName()); for (TFieldIterator<UProperty> It(ScriptStruct); It; ++It) { if (It->PropertyFlags & CPF_RepSkip) { continue; } void* PropertyData = It->ContainerPtrToValuePtr<void*>(ContainerPtr); It->NetSerializeItem(Ar, Map, PropertyData); } } } } //ABILITY_LOG(Warning, TEXT("FGameplayAbilityTargetDataHandle Serialized: %s"), ScriptStruct ? *ScriptStruct->GetName() : TEXT("NULL") ); bOutSuccess = true; return true; }
void FGameplayTagCountContainer::UpdateTagMap_Internal(const FGameplayTag& Tag, int32 CountDelta) { const bool bTagAlreadyExplicitlyExists = ExplicitTags.HasTag(Tag, EGameplayTagMatchType::Explicit, EGameplayTagMatchType::Explicit); // Need special case handling to maintain the explicit tag list correctly, adding the tag to the list if it didn't previously exist and a // positive delta comes in, and removing it from the list if it did exist and a negative delta comes in. if (!bTagAlreadyExplicitlyExists) { // Brand new tag with a positive delta needs to be explicitly added if (CountDelta > 0) { ExplicitTags.AddTag(Tag); } // Block attempted reduction of non-explicit tags, as they were never truly added to the container directly else { // only warn about tags that are in the container but will not be removed because they aren't explicitly in the container if (ExplicitTags.HasTag(Tag, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit)) { ABILITY_LOG(Warning, TEXT("Attempted to remove tag: %s from tag count container, but it is not explicitly in the container!"), *Tag.ToString()); } return; } } // Update the explicit tag count map. This has to be separate than the map below because otherwise the count of nested tags ends up wrong int32& ExistingCount = ExplicitTagCountMap.FindOrAdd(Tag); ExistingCount = FMath::Max(ExistingCount + CountDelta, 0); // If our new count is 0, remove us from the explicit tag list if (ExistingCount <= 0) { // Remove from the explicit list ExplicitTags.RemoveTag(Tag); } // Check if change delegates are required to fire for the tag or any of its parents based on the count change FGameplayTagContainer TagAndParentsContainer = IGameplayTagsModule::Get().GetGameplayTagsManager().RequestGameplayTagParents(Tag); for (auto CompleteTagIt = TagAndParentsContainer.CreateConstIterator(); CompleteTagIt; ++CompleteTagIt) { const FGameplayTag& CurTag = *CompleteTagIt; // Get the current count of the specified tag. NOTE: Stored as a reference, so subsequent changes propogate to the map. int32& TagCount = GameplayTagCountMap.FindOrAdd(CurTag); const int32 OldCount = TagCount; // Apply the delta to the count in the map TagCount = FMath::Max(TagCount + CountDelta, 0); // If a significant change (new addition or total removal) occurred, trigger related delegates if (OldCount == 0 || TagCount == 0) { OnAnyTagChangeDelegate.Broadcast(CurTag, TagCount); FOnGameplayEffectTagCountChanged* CountChangeDelegate = GameplayTagEventMap.Find(CurTag); if (CountChangeDelegate) { CountChangeDelegate->Broadcast(CurTag, TagCount); } } } }
static void FindInvalidScalableFloats(const TArray<FString>& Args, bool ShowCoeffecients) { GCurrentBadScalableFloatList.Empty(); TArray<UClass*> ClassesWithScalableFloats; for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* ThisClass = *ClassIt; if (FindClassesWithScalableFloat_r(Args, ThisClass, ThisClass)) { ClassesWithScalableFloats.Add(ThisClass); ABILITY_LOG(Warning, TEXT("Class has scalable float: %s"), *ThisClass->GetName()); } } for (UClass* ThisClass : ClassesWithScalableFloats) { UObjectLibrary* ObjLibrary = nullptr; TArray<FAssetData> AssetDataList; TArray<FString> Paths; Paths.Add(TEXT("/Game/")); { FString PerfMessage = FString::Printf(TEXT("Loading %s via ObjectLibrary"), *ThisClass->GetName() ); SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr) ObjLibrary = UObjectLibrary::CreateLibrary(ThisClass, true, true); ObjLibrary->LoadBlueprintAssetDataFromPaths(Paths, true); ObjLibrary->LoadAssetsFromAssetData(); ObjLibrary->GetAssetDataList(AssetDataList); ABILITY_LOG( Warning, TEXT("Found: %d %s assets."), AssetDataList.Num(), *ThisClass->GetName()); } for (FAssetData Data: AssetDataList) { UPackage* ThisPackage = Data.GetPackage(); UBlueprint* ThisBlueprint = CastChecked<UBlueprint>(Data.GetAsset()); UClass* AssetClass = ThisBlueprint->GeneratedClass; UObject* ThisCDO = AssetClass->GetDefaultObject(); FString PathName = ThisCDO->GetName(); PathName.RemoveFromStart(TEXT("Default__")); GCurrentBadScalableFloat.Asset = ThisCDO; //ABILITY_LOG( Warning, TEXT("Asset: %s "), *PathName ); CheckForBadScalableFloats_r(ThisCDO, AssetClass, AssetClass); } } ABILITY_LOG( Error, TEXT("")); ABILITY_LOG( Error, TEXT("")); if (ShowCoeffecients == false) { for ( FBadScalableFloat& BadFoo : GCurrentBadScalableFloatList) { ABILITY_LOG( Error, TEXT(", %s, %s, %s,"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String ); } ABILITY_LOG( Error, TEXT("")); ABILITY_LOG( Error, TEXT("%d Errors total"), GCurrentBadScalableFloatList.Num() ); } else { ABILITY_LOG( Error, TEXT("Non 1 coefficients: ")); for ( FBadScalableFloat& BadFoo : GCurrentNaughtyScalableFloatList) { ABILITY_LOG( Error, TEXT(", %s, %s, %s"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String ); } } }
void FActiveGameplayEffect::PrintAll() const { ABILITY_LOG(Log, TEXT("Handle: %s"), *Handle.ToString()); ABILITY_LOG(Log, TEXT("StartWorldTime: %.2f"), StartWorldTime); Spec.PrintAll(); }
bool UAbilityTask_WaitTargetData::BeginSpawningActor(UObject* WorldContextObject, TSubclassOf<AGameplayAbilityTargetActor> TargetClass, AGameplayAbilityTargetActor*& SpawnedActor) { SpawnedActor = nullptr; UGameplayAbility* MyAbility = Ability.Get(); if (MyAbility) { const AGameplayAbilityTargetActor* CDO = CastChecked<AGameplayAbilityTargetActor>(TargetClass->GetDefaultObject()); MyTargetActor = CDO; bool Replicates = CDO->GetReplicates(); bool StaticFunc = CDO->StaticTargetFunction; bool IsLocallyControlled = MyAbility->GetCurrentActorInfo()->IsLocallyControlled(); if (Replicates && StaticFunc) { // We can't replicate a staticFunc target actor, since we are just calling a static function and not spawning an actor at all! ABILITY_LOG(Fatal, TEXT("AbilityTargetActor class %s can't be Replicating and Static"), *TargetClass->GetName()); Replicates = false; } // Spawn the actor if this is a locally controlled ability (always) or if this is a replicating targeting mode. // (E.g., server will spawn this target actor to replicate to all non owning clients) if (Replicates || IsLocallyControlled || CDO->ShouldProduceTargetDataOnServer) { if (StaticFunc) { // This is just a static function that should instantly give us back target data FGameplayAbilityTargetDataHandle Data = CDO->StaticGetTargetData(MyAbility->GetWorld(), MyAbility->GetCurrentActorInfo(), MyAbility->GetCurrentActivationInfo()); OnTargetDataReadyCallback(Data); } else { UClass* Class = *TargetClass; if (Class != NULL) { UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); SpawnedActor = World->SpawnActorDeferred<AGameplayAbilityTargetActor>(Class, FVector::ZeroVector, FRotator::ZeroRotator, NULL, NULL, true); } // If we spawned the target actor, always register the callbacks for when the data is ready. SpawnedActor->TargetDataReadyDelegate.AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataReadyCallback); SpawnedActor->CanceledDelegate.AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataCancelledCallback); MyTargetActor = SpawnedActor; AGameplayAbilityTargetActor* TargetActor = CastChecked<AGameplayAbilityTargetActor>(SpawnedActor); if (TargetActor) { TargetActor->MasterPC = MyAbility->GetCurrentActorInfo()->PlayerController.Get(); } } } // If not locally controlled (server for remote client), see if TargetData was already sent // else register callback for when it does get here. if (!IsLocallyControlled) { // Register with the TargetData callbacks if we are expecting client to send them if (!CDO->ShouldProduceTargetDataOnServer) { // Problem here - if there's targeting data just sitting around, fire events don't get hooked up because of this if-else, even if we don't end the task. if (AbilitySystemComponent->ReplicatedTargetData.IsValid(0)) { ValidData.Broadcast(AbilitySystemComponent->ReplicatedTargetData); if (ConfirmationType == EGameplayTargetingConfirmation::CustomMulti) { //Since multifire is supported, we still need to hook up the callbacks OnTargetDataReplicatedCallbackDelegateHandle = AbilitySystemComponent->ReplicatedTargetDataDelegate.AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCallback); AbilitySystemComponent->ReplicatedTargetDataCancelledDelegate.AddDynamic(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCancelledCallback); } else { EndTask(); } } else { OnTargetDataReplicatedCallbackDelegateHandle = AbilitySystemComponent->ReplicatedTargetDataDelegate.AddUObject(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCallback); AbilitySystemComponent->ReplicatedTargetDataCancelledDelegate.AddDynamic(this, &UAbilityTask_WaitTargetData::OnTargetDataReplicatedCancelledCallback); } } } } return (SpawnedActor != nullptr); }
AGameplayCueNotify_Actor* UGameplayCueManager::GetInstancedCueActor(AActor* TargetActor, UClass* CueClass, const FGameplayCueParameters& Parameters) { QUICK_SCOPE_CYCLE_COUNTER(STAT_GameplayCueManager_GetInstancedCueActor); // First, see if this actor already have a GameplayCueNotifyActor already going for this CueClass AGameplayCueNotify_Actor* CDO = Cast<AGameplayCueNotify_Actor>(CueClass->ClassDefaultObject); FGCNotifyActorKey NotifyKey(TargetActor, CueClass, CDO->bUniqueInstancePerInstigator ? Parameters.GetInstigator() : nullptr, CDO->bUniqueInstancePerSourceObject ? Parameters.GetSourceObject() : nullptr); AGameplayCueNotify_Actor* SpawnedCue = nullptr; if (TWeakObjectPtr<AGameplayCueNotify_Actor>* WeakPtrPtr = NotifyMapActor.Find(NotifyKey)) { SpawnedCue = WeakPtrPtr->Get(); // If the cue is scheduled to be destroyed, don't reuse it, create a new one instead if (SpawnedCue && SpawnedCue->GameplayCuePendingRemove() == false) { if (SpawnedCue->GetOwner() != TargetActor) { // This should not happen. This means we think we can recycle and GC actor that is currently being used by someone else. ABILITY_LOG(Warning, TEXT("GetInstancedCueActor attempting to reuse GC Actor with a different owner! %s (Target: %s). Using GC Actor: %s. Current Owner: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue), *GetNameSafe(SpawnedCue->GetOwner())); } else { UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("::GetInstancedCueActor Using Existing %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue)); return SpawnedCue; } } } // We don't have an instance for this, and we need one, so make one if (ensure(TargetActor) && ensure(CueClass)) { AActor* NewOwnerActor = TargetActor; #if WITH_EDITOR // Don't set owner if we are using fake CDO actor to do anim previewing NewOwnerActor= (TargetActor && TargetActor->HasAnyFlags(RF_ClassDefaultObject) == false ? TargetActor : nullptr); #endif // Look to reuse an existing one that is stored on the CDO: if (GameplayCueActorRecycle > 0) { FPreallocationInfo& Info = GetPreallocationInfo(GetWorld()); TArray<AGameplayCueNotify_Actor*>* PreallocatedList = Info.PreallocatedInstances.Find(CueClass); if (PreallocatedList && PreallocatedList->Num() > 0) { SpawnedCue = PreallocatedList->Pop(false); checkf(SpawnedCue && SpawnedCue->IsPendingKill() == false, TEXT("Spawned Cue is pending kill or null: %s"), *GetNameSafe(SpawnedCue)); SpawnedCue->bInRecycleQueue = false; SpawnedCue->SetActorHiddenInGame(false); SpawnedCue->SetOwner(NewOwnerActor); SpawnedCue->SetActorLocationAndRotation(TargetActor->GetActorLocation(), TargetActor->GetActorRotation()); UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("GetInstancedCueActor Popping Recycled %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue)); #if WITH_EDITOR // let things know that we 'spawned' ISequenceRecorder& SequenceRecorder = FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder"); SequenceRecorder.NotifyActorStartRecording(SpawnedCue); #endif } } // If we can't reuse, then spawn a new one if (SpawnedCue == nullptr) { FActorSpawnParameters SpawnParams; SpawnParams.Owner = NewOwnerActor; if (SpawnedCue == nullptr) { if (LogGameplayCueActorSpawning) { ABILITY_LOG(Warning, TEXT("Spawning GameplaycueActor: %s"), *CueClass->GetName()); } SpawnedCue = GetWorld()->SpawnActor<AGameplayCueNotify_Actor>(CueClass, TargetActor->GetActorLocation(), TargetActor->GetActorRotation(), SpawnParams); } } // Associate this GameplayCueNotifyActor with this target actor/key if (ensure(SpawnedCue)) { SpawnedCue->NotifyKey = NotifyKey; NotifyMapActor.Add(NotifyKey, SpawnedCue); } } UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("GetInstancedCueActor Returning %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue)); return SpawnedCue; }
void UGameplayCueManager::HandleGameplayCue(AActor* TargetActor, FGameplayTag GameplayCueTag, EGameplayCueEvent::Type EventType, const FGameplayCueParameters& Parameters) { if (DisableGameplayCues) { return; } if (GameplayCueRunOnDedicatedServer == 0 && IsDedicatedServerForGameplayCue()) { return; } #if WITH_EDITOR if (GIsEditor && TargetActor == nullptr && UGameplayCueManager::PreviewComponent) { TargetActor = Cast<AActor>(AActor::StaticClass()->GetDefaultObject()); } #endif if (TargetActor == nullptr) { ABILITY_LOG(Warning, TEXT("UGameplayCueManager::HandleGameplayCue called on null TargetActor. GameplayCueTag: %s."), *GameplayCueTag.ToString()); return; } IGameplayCueInterface* GameplayCueInterface = Cast<IGameplayCueInterface>(TargetActor); bool bAcceptsCue = true; if (GameplayCueInterface) { bAcceptsCue = GameplayCueInterface->ShouldAcceptGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } if (DisplayGameplayCues) { FString DebugStr = FString::Printf(TEXT("%s - %s"), *GameplayCueTag.ToString(), *EGameplayCueEventToString(EventType) ); FColor DebugColor = FColor::Green; DrawDebugString(TargetActor->GetWorld(), FVector(0.f, 0.f, 100.f), DebugStr, TargetActor, DebugColor, DisplayGameplayCueDuration); } CurrentWorld = TargetActor->GetWorld(); // Don't handle gameplay cues when world is tearing down if (!GetWorld() || GetWorld()->bIsTearingDown) { return; } // Give the global set a chance check(GlobalCueSet); if (bAcceptsCue) { GlobalCueSet->HandleGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } // Use the interface even if it's not in the map if (GameplayCueInterface && bAcceptsCue) { GameplayCueInterface->HandleGameplayCue(TargetActor, GameplayCueTag, EventType, Parameters); } CurrentWorld = nullptr; }
void UGameplayCueManager::BuildCuesToAddToGlobalSet(const TArray<FAssetData>& AssetDataList, FName TagPropertyName, bool bAsyncLoadAfterAdd, TArray<FGameplayCueReferencePair>& OutCuesToAdd, FOnGameplayCueNotifySetLoaded OnLoaded, FShouldLoadGCNotifyDelegate ShouldLoad) { IGameplayTagsModule& GameplayTagsModule = IGameplayTagsModule::Get(); TArray<FStringAssetReference> AssetsToLoad; AssetsToLoad.Reserve(AssetDataList.Num()); for (FAssetData Data: AssetDataList) { // If ShouldLoad delegate is bound and it returns false, don't load this one if (ShouldLoad.IsBound() && (ShouldLoad.Execute(Data) == false)) { continue; } const FString* FoundGameplayTag = Data.TagsAndValues.Find(TagPropertyName); if (FoundGameplayTag && FoundGameplayTag->Equals(TEXT("None")) == false) { const FString* GeneratedClassTag = Data.TagsAndValues.Find(TEXT("GeneratedClass")); if (GeneratedClassTag == nullptr) { ABILITY_LOG(Warning, TEXT("Unable to find GeneratedClass value for AssetData %s"), *Data.ObjectPath.ToString()); continue; } ABILITY_LOG(Log, TEXT("GameplayCueManager Found: %s / %s"), **FoundGameplayTag, **GeneratedClassTag); FGameplayTag GameplayCueTag = GameplayTagsModule.GetGameplayTagsManager().RequestGameplayTag(FName(**FoundGameplayTag), false); if (GameplayCueTag.IsValid()) { // Add a new NotifyData entry to our flat list for this one FStringAssetReference StringRef; StringRef.SetPath(FPackageName::ExportTextPathToObjectPath(*GeneratedClassTag)); OutCuesToAdd.Add(FGameplayCueReferencePair(GameplayCueTag, StringRef)); AssetsToLoad.Add(StringRef); } else { ABILITY_LOG(Warning, TEXT("Found GameplayCue tag %s in asset %s but there is no corresponding tag in the GameplayTagManager."), **FoundGameplayTag, *Data.PackageName.ToString()); } } } if (bAsyncLoadAfterAdd) { auto ForwardLambda = [](TArray<FStringAssetReference> AssetList, FOnGameplayCueNotifySetLoaded OnLoadedDelegate) { OnLoadedDelegate.ExecuteIfBound(AssetList); }; if (AssetsToLoad.Num() > 0) { StreamableManager.RequestAsyncLoad(AssetsToLoad, FStreamableDelegate::CreateStatic( ForwardLambda, AssetsToLoad, OnLoaded)); } else { // Still fire the delegate even if nothing was found to load OnLoaded.ExecuteIfBound(AssetsToLoad); } } }