예제 #1
0
/**
 * Issues level streaming load/unload requests based on whether
 * players are inside/outside level streaming volumes.
 */
void UWorld::ProcessLevelStreamingVolumes(FVector* OverrideViewLocation)
{
	// if we are delaying using streaming volumes, return now
	if( StreamingVolumeUpdateDelay > 0 )
	{
		StreamingVolumeUpdateDelay--;
		return;
	}
	// Option to skip indefinitely.
	else if( StreamingVolumeUpdateDelay == INDEX_NONE )
	{
		return;
	}

	SCOPE_CYCLE_COUNTER( STAT_VolumeStreamingTickTime );

	// Begin by assembling a list of kismet streaming objects that have non-EditorPreVisOnly volumes associated with them.
	// @todo DB: Cache this, e.g. level startup.
	TArray<ULevelStreaming*> LevelStreamingObjectsWithVolumes;
	TMap<ULevelStreaming*,bool> LevelStreamingObjectsWithVolumesOtherThanBlockingLoad;
	for( int32 LevelIndex = 0 ; LevelIndex < StreamingLevels.Num() ; ++LevelIndex )
	{
		ULevelStreaming* LevelStreamingObject = StreamingLevels[LevelIndex];
		if( LevelStreamingObject )
		{
			for ( int32 i = 0 ; i < LevelStreamingObject->EditorStreamingVolumes.Num() ; ++i )
			{
				ALevelStreamingVolume* StreamingVolume = LevelStreamingObject->EditorStreamingVolumes[i];
				if( StreamingVolume 
				&& !StreamingVolume->bEditorPreVisOnly 
				&& !StreamingVolume->bDisabled )
				{
					LevelStreamingObjectsWithVolumes.Add( LevelStreamingObject );
					if( StreamingVolume->StreamingUsage != SVB_BlockingOnLoad )
					{
						LevelStreamingObjectsWithVolumesOtherThanBlockingLoad.Add( LevelStreamingObject, true );
					}
					break;
				}
			}
		}
	}

	// The set of levels with volumes whose volumes current contain player viewpoints.
	TMap<ULevelStreaming*,FVisibleLevelStreamingSettings> VisibleLevelStreamingObjects;

	// Iterate over all players and build a list of level streaming objects with
	// volumes that contain player viewpoints.
	bool bStreamingVolumesAreRelevant = false;
	for( FConstPlayerControllerIterator Iterator = GetPlayerControllerIterator(); Iterator; ++Iterator )
	{
		APlayerController* PlayerActor = *Iterator;
		if (PlayerActor->bIsUsingStreamingVolumes)
		{
			bStreamingVolumesAreRelevant = true;

			FVector ViewLocation(0,0,0);
			// let the caller override the location to check for volumes
			if (OverrideViewLocation)
			{
				ViewLocation = *OverrideViewLocation;
			}
			else
			{
				FRotator ViewRotation(0,0,0);
				PlayerActor->GetPlayerViewPoint( ViewLocation, ViewRotation );
			}

			TMap<AVolume*,bool> VolumeMap;

			// Iterate over streaming levels with volumes and compute whether the
			// player's ViewLocation is in any of their volumes.
			for( int32 LevelIndex = 0 ; LevelIndex < LevelStreamingObjectsWithVolumes.Num() ; ++LevelIndex )
			{
				ULevelStreaming* LevelStreamingObject = LevelStreamingObjectsWithVolumes[ LevelIndex ];

				// StreamingSettings is an OR of all level streaming settings of volumes containing player viewpoints.
				FVisibleLevelStreamingSettings StreamingSettings;

				// See if level streaming settings were computed for other players.
				FVisibleLevelStreamingSettings* ExistingStreamingSettings = VisibleLevelStreamingObjects.Find( LevelStreamingObject );
				if ( ExistingStreamingSettings )
				{
					// Stop looking for viewpoint-containing volumes once all streaming settings have been enabled for the level.
					if ( ExistingStreamingSettings->AllSettingsEnabled() )
					{
						continue;
					}

					// Initialize the level's streaming settings with settings that were computed for other players.
					StreamingSettings = *ExistingStreamingSettings;
				}

				// For each streaming volume associated with this level . . .
				for ( int32 i = 0 ; i < LevelStreamingObject->EditorStreamingVolumes.Num() ; ++i )
				{
					ALevelStreamingVolume* StreamingVolume = LevelStreamingObject->EditorStreamingVolumes[i];
					if ( StreamingVolume && !StreamingVolume->bEditorPreVisOnly && !StreamingVolume->bDisabled )
					{
						bool bViewpointInVolume;
						bool* bResult = VolumeMap.Find(StreamingVolume);
						if ( bResult )
						{
							// This volume has already been considered for another level.
							bViewpointInVolume = *bResult;
						}
						else
						{						
							// Compute whether the viewpoint is inside the volume and cache the result.
							bViewpointInVolume = StreamingVolume->EncompassesPoint( ViewLocation );								
						
							VolumeMap.Add( StreamingVolume, bViewpointInVolume );
							INC_DWORD_STAT( STAT_VolumeStreamingChecks );
						}

						if ( bViewpointInVolume )
						{
							// Copy off the streaming settings for this volume.
							StreamingSettings |= FVisibleLevelStreamingSettings( (EStreamingVolumeUsage) StreamingVolume->StreamingUsage );

							// Update the streaming settings for the level.
							// This also marks the level as "should be loaded".
							VisibleLevelStreamingObjects.Add( LevelStreamingObject, StreamingSettings );

							// Stop looking for viewpoint-containing volumes once all streaming settings have been enabled.
							if ( StreamingSettings.AllSettingsEnabled() )
							{
								break;
							}
						}
					}
				}
			} // for each streaming level 
		} // bIsUsingStreamingVolumes
	} // for each PlayerController

	// do nothing if no players are using streaming volumes
	if (bStreamingVolumesAreRelevant)
	{
		// Iterate over all streaming levels and set the level's loading status based
		// on whether it was found to be visible by a level streaming volume.
		for( int32 LevelIndex = 0 ; LevelIndex < LevelStreamingObjectsWithVolumes.Num() ; ++LevelIndex )
		{
			ULevelStreaming* LevelStreamingObject = LevelStreamingObjectsWithVolumes[LevelIndex];

			// Figure out whether level should be loaded and keep track of original state for notifications on change.
			FVisibleLevelStreamingSettings* NewStreamingSettings= VisibleLevelStreamingObjects.Find( LevelStreamingObject );
			bool bShouldAffectLoading							= LevelStreamingObjectsWithVolumesOtherThanBlockingLoad.Find( LevelStreamingObject ) != NULL;
			bool bShouldBeLoaded								= (NewStreamingSettings != NULL);
			bool bOriginalShouldBeLoaded						= LevelStreamingObject->bShouldBeLoaded;
			bool bOriginalShouldBeVisible						= LevelStreamingObject->bShouldBeVisible;
			bool bOriginalShouldBlockOnLoad						= LevelStreamingObject->bShouldBlockOnLoad;
			int32 bOriginalLODIndex								= LevelStreamingObject->LevelLODIndex;

			if( bShouldBeLoaded || bShouldAffectLoading )
			{
				if( bShouldBeLoaded )
				{
					// Loading.
					LevelStreamingObject->bShouldBeLoaded		= true;
					LevelStreamingObject->bShouldBeVisible		= NewStreamingSettings->ShouldBeVisible( bOriginalShouldBeVisible );
					LevelStreamingObject->bShouldBlockOnLoad	= NewStreamingSettings->ShouldBlockOnLoad();
				}
				// Prevent unload request flood.  The additional check ensures that unload requests can still be issued in the first UnloadCooldownTime seconds of play.
				else 
				if( TimeSeconds - LevelStreamingObject->LastVolumeUnloadRequestTime > LevelStreamingObject->MinTimeBetweenVolumeUnloadRequests 
				||  LevelStreamingObject->LastVolumeUnloadRequestTime < 0.1f )
				{
					//UE_LOG(LogLevel, Warning, TEXT("Unloading") );
					if( GetPlayerControllerIterator() )
					{
						LevelStreamingObject->LastVolumeUnloadRequestTime	= TimeSeconds;
						LevelStreamingObject->bShouldBeLoaded				= false;
						LevelStreamingObject->bShouldBeVisible				= false;						
					}
				}
			
				// Notify players of the change.
				if( bOriginalShouldBeLoaded		!= LevelStreamingObject->bShouldBeLoaded
				||	bOriginalShouldBeVisible	!= LevelStreamingObject->bShouldBeVisible 
				||	bOriginalShouldBlockOnLoad	!= LevelStreamingObject->bShouldBlockOnLoad
				||  bOriginalLODIndex			!= LevelStreamingObject->LevelLODIndex)
				{
					for( FConstPlayerControllerIterator Iterator = GetPlayerControllerIterator(); Iterator; ++Iterator )
					{
						APlayerController* PlayerController = *Iterator;
						PlayerController->LevelStreamingStatusChanged( 
								LevelStreamingObject, 
								LevelStreamingObject->bShouldBeLoaded, 
								LevelStreamingObject->bShouldBeVisible,
								LevelStreamingObject->bShouldBlockOnLoad,
								LevelStreamingObject->LevelLODIndex);
					}
				}
			}
		}
	}
}
예제 #2
0
//
// ARobotCameraActor::Tick
//
void ARobotCameraActor::Tick( float DeltaSeconds )
{
	auto	World = GetWorld();

	if( World != nullptr )
	{
		// Get each player's pawn and add to the cumulative position. We'll look at the average of
		// this.
		uint8	PositionCount		= 0;

		FVector	MinLocation			= FVector::ZeroVector;
		FVector MaxLocation			= FVector::ZeroVector;
		for( auto Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator )
		{
			auto RobotPlayer = Cast<ARobotPlayerController>( *Iterator );
			if( RobotPlayer == nullptr )
			{
				continue;
			}
			if( !RobotPlayer->GetIsIn() )
			{
				continue;
			}
			
			auto Pawn = RobotPlayer->GetPawn();
			if( Pawn == nullptr )
			{
				continue;
			}

			auto PawnLocation = Pawn->GetActorLocation();
			++PositionCount;

			if( PositionCount == 1 )
			{
				MinLocation = PawnLocation;
				MaxLocation	= PawnLocation;
				continue;
			}

			// Find bounds.
			if( PawnLocation.X < MinLocation.X )
			{
				MinLocation.X = PawnLocation.X;
			}
			if( PawnLocation.X > MaxLocation.X )
			{
				MaxLocation.X = PawnLocation.X;
			}
			if( PawnLocation.Y < MinLocation.Y )
			{
				MinLocation.Y = PawnLocation.Y;
			}
			if( PawnLocation.Y > MaxLocation.Y )
			{
				MaxLocation.Y = PawnLocation.Y;
			}

			// Make sure we look at the top of the box so we can see the entire thing.
			if( PawnLocation.Z > MaxLocation.Z )
			{
				MaxLocation.Z = PawnLocation.Z;
			}
		}

		// Create a box outlining the bounds of each player character. Scale the bounds so characters aren't on the very edge of the screen.
		FVector	Size						= FVector( FMath::Abs( MaxLocation.X - MinLocation.X ), FMath::Abs( MaxLocation.Y - MinLocation.Y ), 0.0f );
		FVector Center						= FVector( MinLocation.X + ( Size.X / 2.0f ), MinLocation.Y + ( Size.Y / 2.0f ), 0.0f );

		FVector	ScaledMax					= MaxLocation * BoundsScale;
		FVector	ScaledMin					= MinLocation * BoundsScale;
		FVector ScaledSize					= Size * BoundsScale;

		// How far do we need to zoom to make sure everyone fits?
		float	MaxHorizontal				= ScaledSize.Y / ( 2 * FMath::Tan( FMath::DegreesToRadians( CameraComponent->FieldOfView / 2 ) ) );
		float	MaxVertical					= ScaledSize.X / ( 2 * FMath::Tan( FMath::DegreesToRadians( ( CameraComponent->FieldOfView / CameraComponent->AspectRatio ) / 2 ) ) );
		float	WantedArmLength				= FMath::Max<float>( MaxHorizontal, MaxVertical );
		NextArmLength						= FMath::Clamp<float>( WantedArmLength, MinArmLength, MaxArmLength );

		// Look at center of the box.
		if( PositionCount != 0 )
		{
			FVector LastLocation	= GetActorLocation();
			NextPosition			= FVector( MaxVertical <= MaxArmLength ? Center.X : LastLocation.X, MaxHorizontal <= MaxArmLength ? Center.Y : LastLocation.Y, MaxLocation.Z );
		}
	}

	// Extrapolate to next length/location.
	SetActorLocation( FMath::Lerp( GetActorLocation(), NextPosition, FMath::Min( DeltaSeconds * ExtrapolateSpeed, 1.0f ) ) );
	SpringArmComponent->TargetArmLength = FMath::Lerp( SpringArmComponent->TargetArmLength, NextArmLength, FMath::Min( DeltaSeconds * ExtrapolateSpeed, 1.0f ) );
}