1
0
KF2-Dev-Scripts/KFGame/Classes/KFDemoRecSpectator.uc
2020-12-13 18:01:13 +03:00

329 lines
8.1 KiB
Ucode

//=============================================================================
// KFDemoRecSpectator
//=============================================================================
// Specator class to support demo recording/playback functionality
// TODO: Can (and probably should) rename this to DemoRecSpecator after
// We get the UDK/UT stuff out of our build folder. Named it KFDemoRecSpectator
// For now to avoid class name conflicts. The functionality in this class
// also needs to be refined for KF2
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// - John "Ramm-Jaeger" Gibson
// Portions based off of DemoRecSpectator Copyright 1998-2012 Epic Games, Inc.
// All Rights Reserved.
//=============================================================================
class KFDemoRecSpectator extends KFPlayerController;
var bool bFindPlayer;
/** local copy of RealViewTarget as the C++ code might clear it in some cases we don't want to for demo spectators */
var PlayerReplicationInfo MyRealViewTarget;
/** if set, camera rotation is always forced to viewtarget rotation */
var config bool bLockRotationToViewTarget;
/** If set, automatically switches players every AutoSwitchPlayerInterval seconds */
var config bool bAutoSwitchPlayers;
/** Interval to use if bAutoSwitchPlayers is TRUE */
var config float AutoSwitchPlayerInterval;
simulated event PostBeginPlay()
{
Super.PostBeginPlay();
if ( PlayerReplicationInfo != None )
{
PlayerReplicationInfo.bOutOfLives = true;
}
}
simulated event ReceivedPlayer()
{
Super.ReceivedPlayer();
// DemoRecSpectators don't go through the login process, so manually call ClientSetHUD()
// so the spectator has it when playing back the demo
if (Role == ROLE_Authority && WorldInfo.Game != None)
{
ClientSetHUD(WorldInfo.Game.HUDType);
}
}
function InitPlayerReplicationInfo()
{
Super.InitPlayerReplicationInfo();
PlayerReplicationInfo.PlayerName = "DemoRecSpectator";
PlayerReplicationInfo.bIsSpectator = true;
PlayerReplicationInfo.bOnlySpectator = true;
PlayerReplicationInfo.bOutOfLives = true;
PlayerReplicationInfo.bWaitingPlayer = false;
}
/** Prevent Scaleform from hogging input so that RypelCam demo playback controls work */
function SetGFxHUD( KFGFxMoviePlayer_HUD NewGFxHud )
{
super.SetGFxHUD( NewGFxHud );
if( NewGFxHud != none )
{
NewGFxHud.bCaptureInput = false;
}
}
exec function Slomo(float NewTimeDilation)
{
WorldInfo.DemoPlayTimeDilation = NewTimeDilation;
}
exec function ViewClass( class<actor> aClass, optional bool bQuiet, optional bool bCheat )
{
local actor other, first;
local bool bFound;
first = None;
ForEach AllActors( aClass, other )
{
if ( bFound || (first == None) )
{
first = other;
if ( bFound )
break;
}
if ( other == ViewTarget )
bFound = true;
}
if ( first != None )
{
SetViewTarget(first);
//SetBehindView(ViewTarget != self);
}
else
SetViewTarget(self);
}
//==== Called during demo playback ============================================
exec function DemoViewNextPlayer()
{
local Pawn P, Pick;
local bool bFound;
// view next player
foreach WorldInfo.AllPawns(class'Pawn', P)
{
if (P.PlayerReplicationInfo != None)
{
if (Pick == None)
{
Pick = P;
}
if (bFound)
{
Pick = P;
break;
}
else
{
bFound = (RealViewTarget == P.PlayerReplicationInfo || ViewTarget == P);
}
}
}
SetViewTarget(Pick);
}
function SetViewTarget(Actor NewViewTarget, optional ViewTargetTransitionParams TransitionParams)
{
Super.SetViewTarget(NewViewTarget, TransitionParams);
// this check is so that a Pawn getting gibbed doesn't break finding that player again
// must manually clear MyRealViewTarget when player controlled switch back to viewing self
if (NewViewTarget != self)
{
MyRealViewTarget = RealViewTarget;
}
}
unreliable server function ServerViewSelf(optional ViewTargetTransitionParams TransitionParams)
{
Super.ServerViewSelf(TransitionParams);
MyRealViewTarget = None;
}
reliable client function ClientSetRealViewTarget(PlayerReplicationInfo NewTarget)
{
SetViewTarget(self); // will find Pawn from RealViewTarget next tick
RealViewTarget = NewTarget;
MyRealViewTarget = NewTarget;
bFindPlayer = (NewTarget == None);
}
function bool SetPause(bool bPause, optional delegate<CanUnpause> CanUnpauseDelegate = CanUnpause)
{
// allow the spectator to pause demo playback
if (WorldInfo.NetMode == NM_Client)
{
WorldInfo.Pauser = (bPause) ? PlayerReplicationInfo : None;
return true;
}
else
{
return false;
}
}
exec function Pause()
{
if (WorldInfo.NetMode == NM_Client)
{
ServerPause();
}
}
auto state Spectating
{
function BeginState(Name PreviousStateName)
{
super.BeginState(PreviousStateName);
if( bAutoSwitchPlayers )
{
SetTimer( AutoSwitchPlayerInterval, true, nameof( DemoViewNextPlayer ) );
}
}
exec function StartFire(optional byte FireModeNum)
{
// SetBehindView(true);
DemoViewNextPlayer();
}
/** used to start out the demo view on the local player - should be called when recording, not playback */
function SendInitialViewTarget()
{
local PlayerController PC;
foreach LocalPlayerControllers(class'PlayerController', PC)
{
if (!PC.PlayerReplicationInfo.bOnlySpectator)
{
ClientSetRealViewTarget(PC.PlayerReplicationInfo);
return;
}
}
// send None so demo playback knows it should just pick the first Pawn it can find
ClientSetRealViewTarget(None);
}
simulated event GetPlayerViewPoint(out vector CameraLocation, out rotator CameraRotation)
{
Global.GetPlayerViewPoint(CameraLocation, CameraRotation);
}
// exec function BehindView()
// {
// SetBehindView(!bBehindView);
// }
event PlayerTick( float DeltaTime )
{
local Pawn P;
Global.PlayerTick( DeltaTime );
// attempt to find a player to view.
if (Role == ROLE_AutonomousProxy)
{
if (RealViewTarget == None && MyRealViewTarget != None)
{
RealViewTarget = MyRealViewTarget;
}
if ((RealViewTarget==None || RealViewTarget==PlayerReplicationInfo) && bFindPlayer)
{
DemoViewNextPlayer();
if (RealViewTarget != None && RealViewTarget != PlayerReplicationInfo)
{
bFindPlayer = false;
}
}
else
{
// reacquire ViewTarget if the player switched Pawns
if ( RealViewTarget != None && RealViewTarget != PlayerReplicationInfo &&
(Pawn(ViewTarget) == None || Pawn(ViewTarget).PlayerReplicationInfo != RealViewTarget) )
{
foreach WorldInfo.AllPawns(class'Pawn', P)
{
if (P.PlayerReplicationInfo == RealViewTarget)
{
SetViewTarget(P);
break;
}
}
}
}
if (Pawn(ViewTarget) != None)
{
TargetViewRotation = ViewTarget.Rotation;
TargetViewRotation.Pitch = Pawn(ViewTarget).RemoteViewPitch << 8;
}
}
}
Begin:
if (Role == ROLE_Authority)
{
// it takes two ticks to guarantee that all the relevant actors have been recorded into the demo
// (necessary for the reference in ClientSetRealViewTarget()'s parameter to be valid during playback)
Sleep(0.0);
Sleep(0.0);
SendInitialViewTarget();
}
}
simulated event GetPlayerViewPoint(out vector CameraLocation, out rotator CameraRotation)
{
// bFreeCamera = (!bLockRotationToViewTarget && (bBehindView || Vehicle(ViewTarget) != None));
Super.GetPlayerViewPoint(CameraLocation, CameraRotation);
}
function UpdateRotation(float DeltaTime)
{
local rotator NewRotation;
if (bLockRotationToViewTarget)
{
SetRotation(ViewTarget.Rotation);
}
else
{
Super.UpdateRotation(DeltaTime);
}
if (Rotation.Roll != 0)
{
NewRotation = Rotation;
NewRotation.Roll = 0;
SetRotation(NewRotation);
}
}
exec function FOV(float F)
{
// skip over neutered kfplayercontroller version
super(PlayerController).FOV(F);
}
defaultproperties
{
RemoteRole=ROLE_AutonomousProxy
bDemoOwner=1
}