#include "UnrealProject.h" #include "BlueprintAbilityLibrary.h" #include "DealDamageProxy.h" #include "AbilityEventGroup.h" #include "AbilityTriggerBase.h" #include "Modifier.h" #include "NetworkCharacter.h" #include "ProjectileBase.h" #include "Class.h" ULib::ULib(const FObjectInitializer& init) : Super(init) { } AActor* ULib::BeginSpawning2(UObject* WorldContextObject, TSubclassOf ActorClass) { return UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform()); } AActor* ULib::FinishSpawning2(class AActor* Actor) { if(!Actor) return nullptr; return UGameplayStatics::FinishSpawningActor(Actor, FTransform()); } AActor* ULib::BeginSpawningGroup(UObject* WorldContextObject, TSubclassOf ActorClass) { if(!WorldContextObject->GetWorld()->GetAuthGameMode()) return nullptr; AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform()); if(!actor) return nullptr; AAbilityEventGroup* newGroup = Cast(actor); check(newGroup); AAbilityEventGroup* parent = Cast(WorldContextObject); //GWPRINT(L"Parent = " + parent); if(!parent) { GWERROR(L"Cannot call FinishSpawningGroup from any other source than AAbilityEventGroup"); newGroup->Destroy(); return nullptr; } parent->TransitionTo(newGroup); return newGroup; } AActor* ULib::FinishSpawningGroup(class AActor* Actor) { if(!Actor) return nullptr; return FinishSpawning2(Actor); } AActor* ULib::BeginSpawningModifier(UObject* WorldContextObject, TSubclassOf ActorClass) { if(!WorldContextObject->GetWorld()->GetAuthGameMode()) return nullptr; AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, FTransform()); if(!actor) return nullptr; AModifier* newModifier = Cast(actor); check(newModifier); ADealDamageProxy* damageProxy = Cast(WorldContextObject); if(damageProxy) { newModifier->character = damageProxy->character; newModifier->abilityInfo = damageProxy->abilityInfo; } else { GWERROR(L"Cannot spawn modifier from a source that is not a ADealDamageProxy"); newModifier->Destroy(); return nullptr; } return newModifier; } AActor* ULib::FinishSpawningModifier(class AActor* Actor, class ANetworkCharacter* target) { if(!IsValid(Actor)) return nullptr; AModifier* mod = Cast(Actor); if(!IsValid(target)) { FString name = ""; if(mod->abilityInfo) name = mod->abilityInfo->GetName(); GWERROR(L"Modifier needs a target (spawned by " + name + L")"); Actor->Destroy(); return nullptr; } //GWPRINT(L"Modifier Target = " + target); ModifierManager* mm = target->GetModifierManager(); if(!mm) { GWWARNING(L"Can't spawn modifier on a target that doesn't have a modifier manager. Might be in the process of destroying"); Actor->Destroy(); return nullptr; } mod->target = target; check(mod); mm->AddModifier(mod); return FinishSpawning2(Actor); } AActor* ULib::BeginSpawningTrigger(UObject* WorldContextObject, TSubclassOf ActorClass, const FTransform& SpawnTransform) { if(!WorldContextObject->GetWorld()->GetAuthGameMode()) return nullptr; AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform); if(!actor) return nullptr; AAbilityTriggerBase* newTrigger = Cast(actor); check(newTrigger); ADealDamageProxy* damageProxy = Cast(WorldContextObject); if(damageProxy) { newTrigger->character = damageProxy->character; newTrigger->abilityInfo = damageProxy->abilityInfo; } else { GWERROR(L"Cannot spawn trigger from a source that is not a ADealDamageProxy"); actor->Destroy(); return nullptr; } return newTrigger; } AActor* ULib::FinishSpawningTrigger(class AActor* Actor, const FTransform & SpawnTransform) { if(!Actor) return nullptr; return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform); } AActor* ULib::BeginSpawningProjectile(UObject* WorldContextObject, TSubclassOf ActorClass, const FTransform& SpawnTransform) { if(!WorldContextObject->GetWorld()->GetAuthGameMode()) return nullptr; AActor* actor = UGameplayStatics::BeginDeferredActorSpawnFromClass(WorldContextObject, ActorClass, SpawnTransform); if(!actor) return nullptr; AProjectileBase* newProjectile = Cast(actor); check(newProjectile); ADealDamageProxy* damageProxy = Cast(WorldContextObject); if(damageProxy) { newProjectile->character = damageProxy->character; newProjectile->abilityInfo = damageProxy->abilityInfo; } else { GWERROR(L"Cannot spawn projectile from a source that is not a ADealDamageProxy"); actor->Destroy(); return nullptr; } return newProjectile; } AActor* ULib::FinishSpawningProjectile(class AActor* Actor, const FTransform& SpawnTransform) { return UGameplayStatics::FinishSpawningActor(Actor, SpawnTransform); } bool ULib::IsContainedInCone(FVector origin, FVector forward, float coneAngle, AActor* other) { if(other->IsPendingKillPending()) return false; //always hits at 360 degrees if(coneAngle >= 360.0f) return true; FVector dist = other->GetActorLocation() - origin; dist.Normalize(); forward.Normalize(); float dot = FVector::DotProduct(dist, forward); float angle = acosf(dot); float tempMaxAngle = coneAngle / 360; tempMaxAngle *= PI; bool ret = tempMaxAngle > angle; return ret; } int32 ULib::CharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius, FCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter) { UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject); check(world); if(world->GetAuthGameMode() == nullptr) return 0; m_overlapResultArray.Empty(); // Get the character ANetworkCharacter* character = Cast(WorldContextObject); if(!character) { ADealDamageProxy* proxy = Cast(WorldContextObject); if(!proxy) { GWERROR(L"CharacterConeOverlap failed, no caller character or proxy"); return 0; } character = proxy->character; } FCollisionShape shape; shape.SetCapsule(coneRadius, 400.0f); TArray overlaps; if(!world->OverlapMultiByObjectType( overlaps, origin, FQuat::Identity, FCollisionObjectQueryParams::AllDynamicObjects, shape, FCollisionQueryParams::DefaultQueryParam)) { return 0; } TArray test; if(callback.IsBound()) { for(int32 i = 0; i < overlaps.Num(); i++) { FOverlapResult& overlap = overlaps[i]; ANetworkCharacter* target = Cast(overlap.GetActor()); if (target && (overlap.Component->GetCollisionProfileName() == FName("Units") || overlap.Component->GetCollisionProfileName() == FName("Players")) && IsContainedInCone(origin, forward, coneAngle, target) && ULib::CheckAbilityFilter(filter, character, target)) { callback.Execute(target); m_overlapResultArray.Add(target); } } } // = test; return overlaps.Num(); } int32 ULib::ClosestCharacterConeOverlap(UObject* WorldContextObject, FVector origin, float coneRadius, FClosestCharacterConeOverlapCallback callback, FVector forward, float coneAngle, EAbilityFilter filter) { UWorld* world = GEngine->GetWorldFromContextObject(WorldContextObject); check(world); if (world->GetAuthGameMode() == nullptr) return 0; // Get the character ANetworkCharacter* character = Cast(WorldContextObject); if (!character) { ADealDamageProxy* proxy = Cast(WorldContextObject); if (!proxy) { GWERROR(L"CharacterConeOverlap failed, no caller character or proxy"); return 0; } character = proxy->character; } FCollisionShape shape; shape.SetCapsule(coneRadius, 400.0f); TArray overlaps; if (!world->OverlapMultiByObjectType( overlaps, origin, FQuat::Identity, FCollisionObjectQueryParams::AllDynamicObjects, shape, FCollisionQueryParams::DefaultQueryParam)) { return 0; } ANetworkCharacter* closest = nullptr; float dist = 9999999999999.0f; if (callback.IsBound()) { for (int32 i = 0; i < overlaps.Num(); i++) { FOverlapResult& overlap = overlaps[i]; ANetworkCharacter* target = Cast(overlap.GetActor()); if (target && IsContainedInCone(origin, forward, coneAngle, target) && ULib::CheckAbilityFilter(filter, character, target)) { if ((target->GetActorLocation() - origin).Size() < dist) { closest = target; dist = (target->GetActorLocation() - origin).Size(); } } } } if(closest) callback.Execute(closest); return overlaps.Num(); } TArray ULib::m_overlapResultArray; bool ULib::CheckAbilityFilter(EAbilityFilter filter, class ANetworkCharacter* self, class ANetworkCharacter* other) { if(!self) return false; if(!other) return false; if(((uint8)filter & ABILITY_FILTER_ENEMY) != 0) { if(self->GetTeam() != other->GetTeam()) return true; } if(((uint8)filter & ABILITY_FILTER_ALLY) != 0) { if(self->GetTeam() == other->GetTeam()) return true; } return false; } TArrayULib::GetCharacterOverlaps() { TArray returnArray; for (ANetworkCharacter* character : m_overlapResultArray) { if(IsValid(character)) returnArray.Add(character); } return returnArray; }