void AFPSGPlayerController::serverPostOnlineMatchHasEnded_Implementation(EEndMatchReason endMatchReason) { //TODO This function may not work if any clients disconnects or connects during game ending? //TODO NOT PRIORITY - Make it impossible to join matches that are in the process of ending //TODO NOT PRIORITY - Call this function repedeatly every second from a timer in case any clients disconnects while match is ending //GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, TEXT("AFPSGPlayerController::serverPostOnlineMatchHasEnded_Implementation")); //Server marks itself or the calling client as finished postMatchEndFinished = true; UWorld* world = GetWorld(); if (world != NULL) { for (FConstPlayerControllerIterator iter = world->GetPlayerControllerIterator(); iter; ++iter) { AFPSGPlayerController* player = Cast<AFPSGPlayerController>(*iter); //If any clients have not yet finished, we exit if (player != NULL && !player->postMatchEndFinished) return; } //GEngine->AddOnScreenDebugMessage(-1, 40.0f, FColor::Cyan, TEXT("All Clients have finished")); //All clients have finished, perform the final work of ending the match AFPSGGameMode* gameMode = world->GetAuthGameMode<AFPSGGameMode>(); if (gameMode != NULL) { gameMode->terminateMatch(endMatchReason); } } }
void AGameSession::HandleMatchHasEnded() { if (STATS && !UE_BUILD_SHIPPING) { if (FParse::Param(FCommandLine::Get(), TEXT("MatchAutoStatCapture"))) { UE_LOG(LogGameSession, Log, TEXT("Match has ended - end automatic stat capture")); GEngine->Exec(GetWorld(), TEXT("stat stopfile")); } } UWorld* World = GetWorld(); if (UOnlineEngineInterface::Get()->DoesSessionExist(World, SessionName)) { for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; if (!PlayerController->IsLocalController()) { PlayerController->ClientEndOnlineSession(); } } FOnlineSessionStartComplete CompletionDelegate = FOnlineSessionEndComplete::CreateUObject(this, &AGameSession::OnEndSessionComplete); UOnlineEngineInterface::Get()->EndSession(World, SessionName, CompletionDelegate); } }
void AGameplayDebuggingReplicator::TickActor(float DeltaTime, enum ELevelTick TickType, FActorTickFunction& ThisTickFunction) { Super::TickActor(DeltaTime, TickType, ThisTickFunction); #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) UWorld* World = GetWorld(); if (!IsGlobalInWorld() || !World || GetNetMode() == ENetMode::NM_Client || !IGameplayDebugger::IsAvailable()) { // global level replicator don't have any local player and it's prepared to work only on servers return; } UGameInstance* GameInstance = World->GetGameInstance(); if (!GameInstance || !World->IsGameWorld()) { return; } PlayerControllersUpdateDelay -= DeltaTime; if (PlayerControllersUpdateDelay <= 0) { for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; Iterator++) { APlayerController* PC = *Iterator; if (PC) { IGameplayDebugger& Debugger = IGameplayDebugger::Get(); Debugger.CreateGameplayDebuggerForPlayerController(PC); } } PlayerControllersUpdateDelay = 5; } #endif }
/** * Handles "Activated" for single ULevelStreaming object. * * @param LevelStreamingObject LevelStreaming object to handle "Activated" for. */ void FStreamLevelAction::ActivateLevel( ULevelStreaming* LevelStreamingObject ) { if( LevelStreamingObject != NULL ) { // Loading. if( bLoading ) { UE_LOG(LogStreaming, Log, TEXT("Streaming in level %s (%s)..."),*LevelStreamingObject->GetName(),*LevelStreamingObject->GetWorldAssetPackageName()); LevelStreamingObject->bShouldBeLoaded = true; LevelStreamingObject->bShouldBeVisible |= bMakeVisibleAfterLoad; LevelStreamingObject->bShouldBlockOnLoad = bShouldBlockOnLoad; } // Unloading. else { UE_LOG(LogStreaming, Log, TEXT("Streaming out level %s (%s)..."),*LevelStreamingObject->GetName(),*LevelStreamingObject->GetWorldAssetPackageName()); LevelStreamingObject->bShouldBeLoaded = false; LevelStreamingObject->bShouldBeVisible = false; } UWorld* LevelWorld = CastChecked<UWorld>(LevelStreamingObject->GetOuter()); // If we have a valid world if(LevelWorld) { // Notify players of the change for( FConstPlayerControllerIterator Iterator = LevelWorld->GetPlayerControllerIterator(); Iterator; ++Iterator ) { APlayerController* PlayerController = *Iterator; UE_LOG(LogLevel, Log, TEXT("ActivateLevel %s %i %i %i"), *LevelStreamingObject->GetWorldAssetPackageName(), LevelStreamingObject->bShouldBeLoaded, LevelStreamingObject->bShouldBeVisible, LevelStreamingObject->bShouldBlockOnLoad ); PlayerController->LevelStreamingStatusChanged( LevelStreamingObject, LevelStreamingObject->bShouldBeLoaded, LevelStreamingObject->bShouldBeVisible, LevelStreamingObject->bShouldBlockOnLoad, INDEX_NONE); } } } else { UE_LOG(LogLevel, Warning, TEXT("Failed to find streaming level object associated with '%s'"), *LevelName.ToString() ); } }
void UConsole::ConsoleCommand(const FString& Command) { // insert into history buffer { HistoryBuffer.Add(Command); NormalizeHistoryBuffer(); } // Save the command history to the INI. SaveConfig(); OutputText(FString::Printf(TEXT("\n>>> %s <<<"), *Command)); UWorld *World = GetOuterUGameViewportClient()->GetWorld(); if(ConsoleTargetPlayer != NULL) { // If there is a console target player, execute the command in the player's context. ConsoleTargetPlayer->PlayerController->ConsoleCommand(Command); } else if(World && World->GetPlayerControllerIterator()) { // If there are any players, execute the command in the first player's context that has a non-null Player. for (auto PCIter = World->GetPlayerControllerIterator(); PCIter; ++PCIter) { APlayerController* PC = *PCIter; if (PC && PC->Player) { PC->ConsoleCommand(Command); break; } } } else { // Otherwise, execute the command in the context of the viewport. GetOuterUGameViewportClient()->ConsoleCommand(Command); } }
void URealmFogofWarManager::CalculateTeamVisibility() { UWorld* gameWorld = IsValid(playerOwner) ? playerOwner->GetWorld() : gameOwner->GetWorld(); if (availableUnits.Num() <= 0) { for (TActorIterator<AGameCharacter> itr(gameWorld); itr; ++itr) availableUnits.AddUnique(*itr); } //update the players with their new sight lists for (FConstPlayerControllerIterator Iterator = gameWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { ARealmPlayerController* pc = Cast<ARealmPlayerController>(*Iterator); if (IsValid(pc) && IsValid(pc->GetPlayerCharacter()) && enemySightLists[pc->GetPlayerCharacter()->GetTeamIndex()].sightList.Num() > 0) pc->sightList = enemySightLists[pc->GetPlayerCharacter()->GetTeamIndex()].sightList; } }
void AGameplayDebuggerPlayerManager::UpdateAuthReplicators() { UWorld* World = GetWorld(); for (int32 Idx = PlayerData.Num() - 1; Idx >= 0; Idx--) { FGameplayDebuggerPlayerData& TestData = PlayerData[Idx]; if (!IsValid(TestData.Replicator) || !IsValid(TestData.Replicator->GetReplicationOwner())) { if (IsValid(TestData.Replicator)) { World->DestroyActor(TestData.Replicator); } if (IsValid(TestData.Controller)) { TestData.Controller->Cleanup(); } PlayerData.RemoveAt(Idx, 1, false); } } for (FConstPlayerControllerIterator It = World->GetPlayerControllerIterator(); It; It++) { APlayerController* TestPC = *It; if (TestPC && !TestPC->IsA<ADebugCameraController>()) { const bool bNeedsReplicator = (GetReplicator(*TestPC) == nullptr); if (bNeedsReplicator) { AGameplayDebuggerCategoryReplicator* Replicator = World->SpawnActorDeferred<AGameplayDebuggerCategoryReplicator>(AGameplayDebuggerCategoryReplicator::StaticClass(), FTransform::Identity); Replicator->SetReplicatorOwner(TestPC); Replicator->FinishSpawning(FTransform::Identity, true); } } } PrimaryActorTick.TickInterval = PlayerData.Num() ? 5.0f : 0.5f; }
void APlayerState::Destroyed() { UWorld* World = GetWorld(); if (World->GameState != NULL) { World->GameState->RemovePlayerState(this); } if( ShouldBroadCastWelcomeMessage(true) ) { for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; if( PlayerController ) { PlayerController->ClientReceiveLocalizedMessage( EngineMessageClass, 4, this); } } } // Remove the player from the online session UnregisterPlayerWithSession(); Super::Destroyed(); }
bool FGameplayDebugger::Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) bool bHandled = false; if (FParse::Command(&Cmd, TEXT("RunEQS")) && InWorld) { APlayerController* MyPC = InWorld->GetGameInstance() ? InWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr; UAISystem* AISys = UAISystem::GetCurrent(*InWorld); UEnvQueryManager* EQS = AISys ? AISys->GetEnvironmentQueryManager() : NULL; if (MyPC && EQS) { AGameplayDebuggingReplicator* DebuggingReplicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(InWorld); It; ++It) { AGameplayDebuggingReplicator* A = *It; if (!A->IsPendingKill()) { DebuggingReplicator = A; if (!DebuggingReplicator->IsGlobalInWorld() && DebuggingReplicator->GetLocalPlayerOwner() == MyPC) { break; } } } UObject* Target = DebuggingReplicator != NULL ? DebuggingReplicator->GetSelectedActorToDebug() : NULL; FString QueryName = FParse::Token(Cmd, 0); if (Target) { AISys->RunEQS(QueryName, Target); } else { MyPC->ClientMessage(TEXT("No debugging target to run EQS")); } } return true; } if (FParse::Command(&Cmd, TEXT("EnableGDT")) == false) { return false; } FString UniquePlayerId = FParse::Token(Cmd, 0); APlayerController* LocalPC = NULL; UWorld* MyWorld = InWorld; if (MyWorld == nullptr) { if (UniquePlayerId.Len() > 0) { // let's find correct world based on Player Id const TIndirectArray<FWorldContext> WorldContexts = GEngine->GetWorldContexts(); for (auto& Context : WorldContexts) { if (Context.WorldType != EWorldType::Game && Context.WorldType != EWorldType::PIE) { continue; } UWorld *CurrentWorld = Context.World(); for (FConstPlayerControllerIterator Iterator = CurrentWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PC = *Iterator; if (PC && PC->PlayerState->UniqueId.ToString() == UniquePlayerId) { LocalPC = PC; MyWorld = PC->GetWorld(); break; } } if (LocalPC && MyWorld) { break; } } } } if (MyWorld == nullptr) { return false; } if (LocalPC == nullptr) { if (UniquePlayerId.Len() > 0) { for (FConstPlayerControllerIterator Iterator = MyWorld->GetPlayerControllerIterator(); Iterator; ++Iterator) { APlayerController* PlayerController = *Iterator; UE_LOG(LogGameplayDebugger, Log, TEXT("- Client: %s"), *PlayerController->PlayerState->UniqueId.ToString()); if (PlayerController && PlayerController->PlayerState->UniqueId.ToString() == UniquePlayerId) { LocalPC = PlayerController; break; } } } if (!LocalPC && MyWorld->GetNetMode() != NM_DedicatedServer) { LocalPC = MyWorld->GetGameInstance() ? MyWorld->GetGameInstance()->GetFirstLocalPlayerController() : nullptr; } } if (LocalPC == nullptr) { return false; } if (MyWorld->GetNetMode() == NM_Client) { AGameplayDebuggingReplicator* Replicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } if (!Replicator) { LocalPC->ClientMessage(TEXT("Enabling GameplayDebugger on server, please wait for replicated data...")); if (LocalPC->PlayerState) { const FString ServerCheatString = FString::Printf(TEXT("cheat EnableGDT %s"), *LocalPC->PlayerState->UniqueId.ToString()); UE_LOG(LogGameplayDebugger, Warning, TEXT("Sending to Server: %s"), *ServerCheatString); LocalPC->ConsoleCommand(*ServerCheatString); bHandled = true; } } else { if (Replicator->IsToolCreated() == false) { Replicator->CreateTool(); } Replicator->EnableTool(); bHandled = true; } } else { UE_LOG(LogGameplayDebugger, Warning, TEXT("Got from client: EnableGDT %s"), *UniquePlayerId); { AGameplayDebuggingReplicator* Replicator = NULL; for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } if (!Replicator) { CreateGameplayDebuggerForPlayerController(LocalPC); for (TActorIterator<AGameplayDebuggingReplicator> It(MyWorld); It; ++It) { Replicator = *It; if (Replicator && !Replicator->IsPendingKill()) { APlayerController* PCOwner = Replicator->GetLocalPlayerOwner(); if (LocalPC == PCOwner) { break; } } Replicator = NULL; } } if (MyWorld->GetNetMode() != NM_DedicatedServer) { if (Replicator && !Replicator->IsToolCreated()) { Replicator->CreateTool(); Replicator->EnableTool(); bHandled = true; } } else { if (Replicator) { Replicator->ClientAutoActivate(); bHandled = true; } } } } return bHandled; #else return false; #endif //!(UE_BUILD_SHIPPING || UE_BUILD_TEST) }
void UParticleModuleCollision::Update(FParticleEmitterInstance* Owner, int32 Offset, float DeltaTime) { SCOPE_CYCLE_COUNTER(STAT_ParticleCollisionTime); check(Owner); check(Owner->Component); UWorld* World = Owner->Component->GetWorld(); if (bDropDetail && World && World->bDropDetail) { return; } //Gets the owning actor of the component. Can be NULL if the component is spawned with the World as an Outer, e.g. in UGameplayStatics::SpawnEmitterAtLocation(). AActor* Actor = Owner->Component->GetOwner(); UParticleLODLevel* LODLevel = Owner->SpriteTemplate->GetCurrentLODLevel(Owner); check(LODLevel); const int32 MeshRotationOffset = Owner->GetMeshRotationOffset(); const bool bMeshRotationActive = Owner->IsMeshRotationActive(); FVector ParentScale = FVector(1.0f, 1.0f, 1.0f); if (Owner->Component) { ParentScale = Owner->Component->ComponentToWorld.GetScale3D(); } FParticleEventInstancePayload* EventPayload = NULL; if (LODLevel->EventGenerator) { EventPayload = (FParticleEventInstancePayload*)(Owner->GetModuleInstanceData(LODLevel->EventGenerator)); if (EventPayload && (EventPayload->bCollisionEventsPresent == false) && (EventPayload->bDeathEventsPresent == false)) { EventPayload = NULL; } } FParticleCollisionInstancePayload* CollisionInstPayload = (FParticleCollisionInstancePayload*)(Owner->GetModuleInstanceData(this)); TArray<FVector> PlayerLocations; TArray<float> PlayerLODDistanceFactor; int32 PlayerCount = 0; if (Owner->GetWorld()->IsGameWorld()) { bool bIgnoreAllCollision = false; // LOD collision based on visibility // This is at the 'emitter instance' level as it will be true or false for the whole instance... if (bCollideOnlyIfVisible && ((World->TimeSeconds - Owner->Component->LastRenderTime) > 0.1f)) { // no collision if not recently rendered bIgnoreAllCollision = true; } else { // If the MaxCollisionDistance is greater than WORLD_MAX, they obviously want the check disabled... if (MaxCollisionDistance < WORLD_MAX) { // Store off the player locations and LOD distance factors for( FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator ) { APlayerController* PlayerController = *Iterator; if (PlayerController->IsLocalPlayerController()) { FVector POVLoc; FRotator POVRotation; PlayerController->GetPlayerViewPoint(POVLoc, POVRotation); PlayerLocations.Add(POVLoc); PlayerLODDistanceFactor.Add(PlayerController->LocalPlayerCachedLODDistanceFactor); } } PlayerCount = PlayerLocations.Num(); // If we have at least a few particles, do a simple check vs. the bounds if (Owner->ActiveParticles > 7) { if (CollisionInstPayload->CurrentLODBoundsCheckCount == 0) { FBox BoundingBox; BoundingBox.Init(); if (Owner->Component->Template && Owner->Component->Template->bUseFixedRelativeBoundingBox) { BoundingBox = Owner->Component->Template->FixedRelativeBoundingBox.TransformBy(Owner->Component->ComponentToWorld); } else { // A frame behind, but shouldn't be an issue... BoundingBox = Owner->Component->Bounds.GetBox(); } // see if any player is within the extended bounds... bIgnoreAllCollision = true; // Check for the system itself beyond beyond the bounds // LOD collision by distance bool bCloseEnough = false; for (int32 PlyrIdx = 0; PlyrIdx < PlayerCount; PlyrIdx++) { // Invert the LOD distance factor here because we are using it to *expand* the // bounds rather than shorten the distance checked as it is usually used for. float InvDistanceFactor = 1.0f / PlayerLODDistanceFactor[PlyrIdx]; FBox CheckBounds = BoundingBox; float BoxExpansionValue = MaxCollisionDistance * InvDistanceFactor; BoxExpansionValue += BoxExpansionValue * 0.075f; // Expand it by the max collision distance (and a little bit extra) CheckBounds = CheckBounds.ExpandBy(BoxExpansionValue); if (CheckBounds.IsInside(PlayerLocations[PlyrIdx])) { // If one is close enough, that's all it takes! bCloseEnough = true; break; } } if (bCloseEnough == true) { bIgnoreAllCollision = false; } } CollisionInstPayload->CurrentLODBoundsCheckCount++; // Every 30 frames recheck the overall bounds... if (CollisionInstPayload->CurrentLODBoundsCheckCount > 30) { CollisionInstPayload->CurrentLODBoundsCheckCount = 0; } } } } if (bIgnoreAllCollision == true) { // Turn off collision on *all* existing particles... // We don't want it to turn back on and have particles // already embedded start performing collision checks. BEGIN_UPDATE_LOOP; { Particle.Flags |= STATE_Particle_IgnoreCollisions; } END_UPDATE_LOOP; return; } // Square the LODDistanceFactor values now, so we don't have to do it // per particle in the update loop below... for (int32 SquareIdx = 0; SquareIdx < PlayerLocations.Num(); SquareIdx++) { PlayerLODDistanceFactor[SquareIdx] *= PlayerLODDistanceFactor[SquareIdx]; } } float SquaredMaxCollisionDistance = FMath::Square(MaxCollisionDistance); BEGIN_UPDATE_LOOP; { if ((Particle.Flags & STATE_Particle_CollisionIgnoreCheck) != 0) { CONTINUE_UPDATE_LOOP; } PARTICLE_ELEMENT(FParticleCollisionPayload, CollisionPayload); if ((Particle.Flags & STATE_Particle_DelayCollisions) != 0) { if (CollisionPayload.Delay > Particle.RelativeTime) { CONTINUE_UPDATE_LOOP; } Particle.Flags &= ~STATE_Particle_DelayCollisions; } FVector Location; FVector OldLocation; // Location won't be calculated till after tick so we need to calculate an intermediate one here. Location = Particle.Location + Particle.Velocity * DeltaTime; if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the location and old location into world space Location = Owner->Component->ComponentToWorld.TransformPosition(Location); OldLocation = Owner->Component->ComponentToWorld.TransformPosition(Particle.OldLocation); } else { OldLocation = Particle.OldLocation; } FVector Direction = (Location - OldLocation).GetSafeNormal(); // Determine the size FVector Size = Particle.Size * ParentScale; FVector Extent(0.0f); // Setup extent for mesh particles. UParticleModuleTypeDataMesh* MeshType = Cast<UParticleModuleTypeDataMesh>(LODLevel->TypeDataModule); if (MeshType && MeshType->Mesh) { Extent = MeshType->Mesh->GetBounds().BoxExtent; } FHitResult Hit; Hit.Normal.X = 0.0f; Hit.Normal.Y = 0.0f; Hit.Normal.Z = 0.0f; check( Owner->Component ); FVector End = Location + Direction * Size / DirScalar; if ((Owner->GetWorld()->IsGameWorld() == true) && (MaxCollisionDistance < WORLD_MAX)) { // LOD collision by distance bool bCloseEnough = false; for (int32 CheckIdx = 0; CheckIdx < PlayerCount; CheckIdx++) { float CheckValue = (PlayerLocations[CheckIdx] - End).SizeSquared() * PlayerLODDistanceFactor[CheckIdx]; if (CheckValue < SquaredMaxCollisionDistance) { bCloseEnough = true; break; } } if (bCloseEnough == false) { Particle.Flags |= STATE_Particle_IgnoreCollisions; CONTINUE_UPDATE_LOOP; } } AActor* IgnoreActor = bIgnoreSourceActor ? Actor : NULL; if (PerformCollisionCheck(Owner, &Particle, Hit, IgnoreActor, End, OldLocation, Extent)) { bool bDecrementMaxCount = true; bool bIgnoreCollision = false; if (Hit.GetActor()) { bDecrementMaxCount = !bPawnsDoNotDecrementCount || !Cast<APawn>(Hit.GetActor()); bIgnoreCollision = Hit.GetActor()->IsA(ATriggerBase::StaticClass()); //@todo.SAS. Allow for PSys to say what it wants to collide w/? } if (bIgnoreCollision == false) { if (bDecrementMaxCount && (bOnlyVerticalNormalsDecrementCount == true)) { if ((Hit.Normal.IsNearlyZero() == false) && (FMath::Abs(Hit.Normal.Z) + VerticalFudgeFactor) < 1.0f) { //UE_LOG(LogParticles, Log, TEXT("Particle from %s had a non-vertical hit!"), *(Owner->Component->Template->GetPathName())); bDecrementMaxCount = false; } } if (bDecrementMaxCount) { CollisionPayload.UsedCollisions--; } if (CollisionPayload.UsedCollisions > 0) { if (LODLevel->RequiredModule->bUseLocalSpace) { // Transform the particle velocity to world space FVector OldVelocity = Owner->Component->ComponentToWorld.TransformVector(Particle.Velocity); FVector BaseVelocity = Owner->Component->ComponentToWorld.TransformVector(Particle.BaseVelocity); BaseVelocity = BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseVelocity = Owner->Component->ComponentToWorld.InverseTransformVector(BaseVelocity); Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector NewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; // New location FVector NewLocation = Location + NewVelocity * (1.f - Hit.Time); Particle.Location = Owner->Component->ComponentToWorld.InverseTransformPosition(NewLocation); if (bApplyPhysics) { UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(NewVelocity - OldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } else { FVector vOldVelocity = Particle.Velocity; // Reflect base velocity and apply damping factor. Particle.BaseVelocity = Particle.BaseVelocity.MirrorByVector(Hit.Normal) * CollisionPayload.UsedDampingFactor; Particle.BaseRotationRate = Particle.BaseRotationRate * CollisionPayload.UsedDampingFactorRotation.X; if (bMeshRotationActive && MeshRotationOffset > 0) { FMeshRotationPayloadData* PayloadData = (FMeshRotationPayloadData*)((uint8*)&Particle + MeshRotationOffset); PayloadData->RotationRateBase *= CollisionPayload.UsedDampingFactorRotation; } // Reset the current velocity and manually adjust location to bounce off based on normal and time of collision. FVector vNewVelocity = Direction.MirrorByVector(Hit.Normal) * (Location - OldLocation).Size() * CollisionPayload.UsedDampingFactor; Particle.Velocity = FVector::ZeroVector; Particle.Location += vNewVelocity * (1.f - Hit.Time); if (bApplyPhysics) { UPrimitiveComponent* PrimitiveComponent = Hit.Component.Get(); if(PrimitiveComponent && PrimitiveComponent->IsAnySimulatingPhysics()) { FVector vImpulse; vImpulse = -(vNewVelocity - vOldVelocity) * ParticleMass.GetValue(Particle.RelativeTime, Owner->Component); PrimitiveComponent->AddImpulseAtLocation(vImpulse, Hit.Location, Hit.BoneName); } } } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } else { if (LODLevel->RequiredModule->bUseLocalSpace == true) { Size = Owner->Component->ComponentToWorld.TransformVector(Size); } Particle.Location = Hit.Location + (Size / 2.0f); if (LODLevel->RequiredModule->bUseLocalSpace == true) { // We need to transform the location back relative to the PSys. // NOTE: LocalSpace makes sense only for stationary emitters that use collision. Particle.Location = Owner->Component->ComponentToWorld.InverseTransformPosition(Particle.Location); } switch (CollisionCompletionOption) { case EPCC_Kill: { if (EventPayload && (EventPayload->bDeathEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleKilled(Owner, EventPayload, &Particle); } KILL_CURRENT_PARTICLE; } break; case EPCC_Freeze: { Particle.Flags |= STATE_Particle_Freeze; } break; case EPCC_HaltCollisions: { Particle.Flags |= STATE_Particle_IgnoreCollisions; } break; case EPCC_FreezeTranslation: { Particle.Flags |= STATE_Particle_FreezeTranslation; } break; case EPCC_FreezeRotation: { Particle.Flags |= STATE_Particle_FreezeRotation; } break; case EPCC_FreezeMovement: { Particle.Flags |= STATE_Particle_FreezeRotation; Particle.Flags |= STATE_Particle_FreezeTranslation; } break; } if (EventPayload && (EventPayload->bCollisionEventsPresent == true)) { LODLevel->EventGenerator->HandleParticleCollision(Owner, EventPayload, &CollisionPayload, &Hit, &Particle, Direction); } } Particle.Flags |= STATE_Particle_CollisionHasOccurred; } } } END_UPDATE_LOOP; }