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

322 lines
8.9 KiB
Ucode

//=============================================================================
// SavedMove is used during network play to buffer recent client moves,
// for use when the server modifies the clients actual position, etc.
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
//=============================================================================
class SavedMove extends Object
native;
// also stores info in Acceleration attribute
var SavedMove NextMove; // Next move in linked list.
var float TimeStamp; // Time of this move.
var float Delta; // amount of time for this move
var bool bRun;
var bool bDuck;
var bool bPressedJump;
var bool bDoubleJump;
var bool bPreciseDestination;
var bool bForceRMVelocity; // client-side only (for replaying moves) - not replicated
var bool bForceMaxAccel;
var EDoubleClickDir DoubleClickMove; // Double click info.
var EPhysics SavedPhysics;
var vector StartLocation, StartRelativeLocation, StartVelocity, StartFloor, SavedLocation, SavedVelocity, SavedRelativeLocation, RMVelocity, Acceleration;
var rotator Rotation;
var Actor StartBase, EndBase;
var float CustomTimeDilation;
var float AccelDotThreshold; // threshold for deciding this is an "important" move based on DP with last acked acceleration
// Root motion correction variables
var bool bRootMotionFromInterpCurve;
var float RootMotionInterpCurrentTime;
var Vector RootMotionInterpCurveLastValue;
var ERootMotionMode RootMotionMode;
`if(`__TW_)
// Put here to avoid casting
// Recoil system
var rotator WeaponBufferRotation;
`endif
function Clear()
{
TimeStamp = 0;
Delta = 0;
DoubleClickMove = DCLICK_None;
Acceleration = vect(0,0,0);
StartVelocity = vect(0,0,0);
bRun = false;
bDuck = false;
bPressedJump = false;
bDoubleJump = false;
bPreciseDestination = false;
bForceRMVelocity = false;
CustomTimeDilation = 1.0;
}
function PostUpdate(PlayerController P)
{
bDoubleJump = P.bDoubleJump || bDoubleJump;
if ( P.Pawn != None )
{
RMVelocity = P.Pawn.RMVelocity;
SavedLocation = P.Pawn.Location;
SavedVelocity = P.Pawn.Velocity;
EndBase = P.Pawn.Base;
if ( (EndBase != None) && !EndBase.bWorldGeometry )
SavedRelativeLocation = P.Pawn.Location - EndBase.Location;
}
Rotation = P.Rotation;
`if(`__TW_)
// Save the WeaponBufferRotation
WeaponBufferRotation = P.WeaponBufferRotation;
`endif
}
function bool IsImportantMove(vector CompareAccel)
{
local vector AccelNorm;
// check if any important movement flags set
if ( bPressedJump ||
bDoubleJump ||
((DoubleClickMove != DCLICK_None) && (DoubleClickMove != DCLICK_Active) && (DoubleClickMove != DCLICK_Done)) )
{
return true;
}
if( bRootMotionFromInterpCurve )
{
return TRUE;
}
// check if acceleration has changed significantly
AccelNorm = Normal(Acceleration);
return ( (CompareAccel != AccelNorm) && ((CompareAccel Dot AccelNorm) < AccelDotThreshold) );
}
function vector GetStartLocation()
{
if( (StartBase != None) && !StartBase.bWorldGeometry )
{
return StartBase.Location + StartRelativeLocation;
}
return StartLocation;
}
function SetInitialPosition(Pawn P)
{
SavedPhysics = P.Physics;
StartLocation = P.Location;
StartVelocity = P.Velocity;
StartBase = P.Base;
StartFloor = P.Floor;
CustomTimeDilation = P.CustomTimeDilation;
if( (StartBase != None) && !StartBase.bWorldGeometry )
{
StartRelativeLocation = P.Location - StartBase.Location;
}
// Store root motion information
bRootMotionFromInterpCurve = P.bRootMotionFromInterpCurve;
if( bRootMotionFromInterpCurve )
{
RootMotionInterpCurrentTime = P.RootMotionInterpCurrentTime;
RootMotionInterpCurveLastValue = P.RootMotionInterpCurveLastValue;
RootMotionMode = P.Mesh.RootMotionMode;
}
}
function bool CanCombineWith(SavedMove NewMove, Pawn InPawn, float MaxDelta)
{
if( InPawn == None )
{
return FALSE;
}
if( bRootMotionFromInterpCurve )
{
return FALSE;
}
if ( NewMove.Acceleration == vect(0,0,0) )
{
return ( (Acceleration == vect(0,0,0))
&& (StartVelocity == vect(0,0,0))
&& (NewMove.StartVelocity == vect(0,0,0))
&& (SavedPhysics == InPawn.Physics)
&& !bPressedJump && !NewMove.bPressedJump
&& (bRun == NewMove.bRun)
&& (bDuck == NewMove.bDuck)
&& (bPreciseDestination == NewMove.bPreciseDestination)
&& (bDoubleJump == NewMove.bDoubleJump)
&& ((DoubleClickMove == DCLICK_None) || (DoubleClickMove == DCLICK_Active))
&& (NewMove.DoubleClickMove == DoubleClickMove)
&& !bForceRMVelocity && !NewMove.bForceRMVelocity)
&& (CustomTimeDilation == NewMove.CustomTimeDilation);
}
else
{
return ( (InPawn != None)
&& (NewMove.Delta + Delta < MaxDelta)
&& (SavedPhysics == InPawn.Physics)
&& !bPressedJump && !NewMove.bPressedJump
&& (bRun == NewMove.bRun)
&& (bDuck == NewMove.bDuck)
&& (bDoubleJump == NewMove.bDoubleJump)
&& (bPreciseDestination == NewMove.bPreciseDestination)
&& ((DoubleClickMove == DCLICK_None) || (DoubleClickMove == DCLICK_Active))
&& (NewMove.DoubleClickMove == DoubleClickMove)
&& ((Normal(Acceleration) Dot Normal(NewMove.Acceleration)) > 0.99)
&& !bForceRMVelocity && !NewMove.bForceRMVelocity)
&& (CustomTimeDilation == NewMove.CustomTimeDilation);
}
}
function SetMoveFor(PlayerController P, float DeltaTime, vector NewAccel, EDoubleClickDir InDoubleClick)
{
Delta = DeltaTime;
// NOTE: max replicated vector component magnitude is 2^18, and acceleration is multiplied by 10 before replication
// quick check to make sure we never cross this limit of 2^18/10
if( VSize(NewAccel) > 26214 )
{
NewAccel = 26214 * Normal(NewAccel);
}
if( P.Pawn != None )
{
SetInitialPosition(P.Pawn);
}
Acceleration = NewAccel;
DoubleClickMove = InDoubleClick;
bRun = (P.bRun > 0);
bDuck = (P.bDuck > 0);
bPressedJump = P.bPressedJump;
bDoubleJump = P.bDoubleJump;
bPreciseDestination = P.bPreciseDestination;
bForceRMVelocity = P.bPreciseDestination ||
(P.Pawn != None && P.Pawn.Mesh != None && !P.Pawn.bRootMotionFromInterpCurve &&
(P.Pawn.Mesh.RootMotionMode == RMM_Accel || P.Pawn.Mesh.RootMotionMode == RMM_Velocity));
bForceMaxAccel = P.Pawn != None && P.Pawn.bForceMaxAccel;
TimeStamp = P.WorldInfo.TimeSeconds;
}
/**
* Called before PlayerController.ClientUpdatePosition uses this SavedMove to make a predictive correction
*/
function PrepMoveFor( Pawn P )
{
if( P != None )
{
P.bForceRMVelocity = bForceRMVelocity;
P.bForceMaxAccel = bForceMaxAccel;
// Reset root motion information
P.bRootMotionFromInterpCurve = bRootMotionFromInterpCurve;
if( P.bRootMotionFromInterpCurve )
{
P.Mesh.RootMotionMode = RootMotionMode;
P.RootMotionInterpCurveLastValue = RootMotionInterpCurveLastValue;
P.SetRootMotionInterpCurrentTime( RootMotionInterpCurrentTime, Delta, TRUE );
}
}
}
/**
* Called after PlayerController.ClientUpdatePosition used this SavedMove to make a predictive correction
*/
function ResetMoveFor( Pawn P )
{
if( P != None )
{
SavedLocation = P.Location;
SavedVelocity = P.Velocity;
EndBase = P.Base;
if( EndBase != None && !EndBase.bWorldGeometry )
{
SavedRelativeLocation = P.Location - EndBase.Location;
}
P.bForceRMVelocity = false;
}
}
/* CompressedFlags()
returns a byte containing encoded special movement information (jumping, crouching, etc.)
SetFlags() and UnCompressFlags() should be overridden to allow game specific special movement information
*/
function byte CompressedFlags()
{
local byte Result;
Result = DoubleClickMove;
if ( bRun )
Result += 8;
if ( bDuck )
Result += 16;
if ( bPressedJump )
Result += 32;
if ( bDoubleJump )
Result += 64;
if ( bPreciseDestination )
Result += 128;
return Result;
}
/* SetFlags()
Set the movement parameters for PC based on the passed in Flags
*/
static function EDoubleClickDir SetFlags(byte Flags, PlayerController PC)
{
if ( (Flags & 8) != 0 )
PC.bRun = 1;
else
PC.bRun = 0;
if ( (Flags & 16) != 0 )
PC.bDuck = 1;
else
PC.bDuck = 0;
PC.bPreciseDestination = ( (Flags & 128) != 0 );
PC.bDoubleJump = ( (Flags & 64) != 0 );
PC.bPressedJump = ( (Flags & 32) != 0 );
switch (Flags & 7)
{
case 0:
return DCLICK_None;
break;
case 1:
return DCLICK_Left;
break;
case 2:
return DCLICK_Right;
break;
case 3:
return DCLICK_Forward;
break;
case 4:
return DCLICK_Back;
break;
}
return DCLICK_None;
}
function String GetDebugString()
{
local String Str;
Str = self@`showvar(Delta)@`showvar(SavedPhysics)@`showvar(StartLocation)@`showvar(StartVelocity)@`showvar(SavedLocation)@`showvar(SavedVelocity)@`showvar(RMVelocity)@`showvar(Acceleration)@`showvar(bRootMotionFromInterpCurve)@`showvar(RootMotionInterpCurrentTime);
return Str;
}
defaultproperties
{
AccelDotThreshold=+0.9
}