1
0
KF2-Dev-Scripts/Engine/Classes/PlayerInput.uc

584 lines
16 KiB
Ucode
Raw Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// PlayerInput
// Object within playercontroller that manages player input.
// only spawned on client
// Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
//=============================================================================
class PlayerInput extends Input within PlayerController
config(Input)
transient
native(UserInterface);
cpptext
{
/**
* Generates an IE_Released event for each key in the PressedKeys array, then clears the array. Should be called when another
* interaction which swallows some (but perhaps not all) input is activated.
*/
virtual void FlushPressedKeys();
/** Override to detect input from a gamepad */
virtual UBOOL InputKey(INT ControllerId, FName Key, enum EInputEvent Event, FLOAT AmountDepressed = 1.f, UBOOL bGamepad = FALSE );
virtual UBOOL InputAxis(INT ControllerId, FName Key, FLOAT Delta, FLOAT DeltaTime, UBOOL bGamepad=FALSE);
virtual UBOOL InputTouch(INT ControllerId, UINT Handle, ETouchType Type, FVector2D TouchLocation, DOUBLE DeviceTimestamp, UINT TouchpadIndex=0);
virtual UBOOL InputMotion(INT ControllerId, const FVector& Tilt, const FVector& RotationRate, const FVector& Gravity, const FVector& Acceleration);
virtual void UpdateAxisValue( FLOAT* Axis, FLOAT Delta );
virtual UBOOL IsGamepadKey(FName Name) const;
}
/** Player is giving input through a gamepad */
var const bool bUsingGamepad;
var const Name LastAxisKeyName;
var globalconfig bool bInvertMouse; /** if true, mouse y axis is inverted from normal FPS mode */
var globalconfig bool bInvertTurn; /** if true, mouse x axis is inverted from normal FPS mode */
// Double click move flags
var bool bWasForward;
var bool bWasBack;
var bool bWasLeft;
var bool bWasRight;
var bool bEdgeForward;
var bool bEdgeBack;
var bool bEdgeLeft;
var bool bEdgeRight;
var float DoubleClickTimer; /** max double click interval for double click move */
var globalconfig float DoubleClickTime; /** stores time of first click for potential double click */
var globalconfig float MouseSensitivity;
// Input axes.
var input float aBaseX;
var input float aBaseY;
var input float aBaseZ;
var input float aMouseX;
var input float aMouseY;
var input float aForward;
var input float aTurn;
var input float aStrafe;
var input float aUp;
var input float aLookUp;
// analog trigger axes
var input float aRightAnalogTrigger;
var input float aLeftAnalogTrigger;
// PS3 SIXAXIS axes
var input float aPS3AccelX;
var input float aPS3AccelY;
var input float aPS3AccelZ;
var input float aPS3Gyro;
// WiiU IR Pointer
var input float aWiiUPointerX;
var input float aWiiUPointerY;
// device tilt - NOTE: These are set directly, they DO NOT go through the .ini Bindings
var input vector aTilt;
var input vector aRotationRate;
var input vector aGravity;
var input vector aAcceleration;
// touch locations, the Z component is > 0 if the touch is currently held down
var input vector aTouch[5];
var input vector aBackTouch[5];
//
// Joy Raw Input
//
/** Joypad left thumbstick, vertical axis. Range [-1,+1] */
var transient float RawJoyUp;
/** Joypad left thumbstick, horizontal axis. Range [-1,+1] */
var transient float RawJoyRight;
/** Joypad right thumbstick, horizontal axis. Range [-1,+1] */
var transient float RawJoyLookRight;
/** Joypad right thumbstick, vertical axis. Range [-1,+1] */
var transient float RawJoyLookUp;
/** move forward speed scaling */
var() config float MoveForwardSpeed;
/** strafe speed scaling */
var() config float MoveStrafeSpeed;
/** Yaw turn speed scaling */
var() config float LookRightScale;
/** pitch turn speed scaling */
var() config float LookUpScale;
// Input buttons.
var input byte bStrafe;
var input byte bXAxis;
var input byte bYAxis;
// Mouse smoothing control
var globalconfig bool bEnableMouseSmoothing; /** if true, mouse smoothing is enabled */
// Zoom Scaling
var bool bEnableFOVScaling;
// Mouse smoothing sample data
var float ZeroTime[2]; /** How long received mouse movement has been zero. */
var float SmoothedMouse[2]; /** Current average mouse movement/sample */
var int MouseSamples; /** Number of mouse samples since mouse movement has been zero */
var float MouseSamplingTotal; /** DirectInput's mouse sampling total time */
/** If TRUE turn input will be ignored until the stick is released */
var transient bool bLockTurnUntilRelease;
/** Time remaining to disable bLockTurnUntilRelease */
var transient float AutoUnlockTurnTime;
/**
* Function to cancel all mobile input before a Scaleform movie confuses the state
*/
native function CancelMobileInput();
//=============================================================================
// Input related functions.
exec function bool InvertMouse()
{
bInvertMouse = !bInvertMouse;
SaveConfig();
return bInvertMouse;
}
exec function bool InvertTurn()
{
bInvertTurn = !bInvertTurn;
SaveConfig();
return bInvertTurn;
}
exec function SetSensitivity(Float F)
{
MouseSensitivity = F;
}
/** Hook called from HUD actor. Gives access to HUD and Canvas */
function DrawHUD( HUD H );
function PreProcessInput(float DeltaTime);
function PostProcessInput(float DeltaTime);
function AdjustMouseSensitivity(float FOVScale)
{
// Apply mouse sensitivity.
aMouseX *= MouseSensitivity * FOVScale;
aMouseY *= MouseSensitivity * FOVScale;
}
// Postprocess the player's input.
event PlayerInput( float DeltaTime )
{
local float FOVScale, TimeScale;
// Save Raw values
RawJoyUp = aBaseY;
RawJoyRight = aStrafe;
RawJoyLookRight = aTurn;
RawJoyLookUp = aLookUp;
// PlayerInput shouldn't take timedilation into account
DeltaTime /= WorldInfo.TimeDilation;
if (Outer.bDemoOwner && WorldInfo.NetMode == NM_Client)
{
DeltaTime /= WorldInfo.DemoPlayTimeDilation;
}
PreProcessInput( DeltaTime );
// Scale to game speed
TimeScale = 100.f*DeltaTime;
aBaseY *= TimeScale * MoveForwardSpeed;
aStrafe *= TimeScale * MoveStrafeSpeed;
aUp *= TimeScale * MoveStrafeSpeed;
aTurn *= TimeScale * LookRightScale;
aLookUp *= TimeScale * LookUpScale;
PostProcessInput( DeltaTime );
ProcessInputMatching(DeltaTime);
// Check for Double click movement.
CatchDoubleClickInput();
// Take FOV into account (lower FOV == less sensitivity).
if ( bEnableFOVScaling )
{
FOVScale = GetFOVAngle() * 0.01111; // 0.01111 = 1 / 90.0
}
else
{
FOVScale = 1.0;
}
AdjustMouseSensitivity(FOVScale);
// mouse smoothing
if ( bEnableMouseSmoothing )
{
aMouseX = SmoothMouse(aMouseX, DeltaTime,bXAxis,0);
aMouseY = SmoothMouse(aMouseY, DeltaTime,bYAxis,1);
}
aLookUp *= FOVScale;
aTurn *= FOVScale;
// Turning and strafing share the same axis.
if( bStrafe > 0 )
aStrafe += aBaseX + aMouseX;
else
aTurn += aBaseX + aMouseX;
// Look up/down.
aLookup += aMouseY;
if (bInvertMouse)
{
aLookup *= -1.f;
}
if (bInvertTurn)
{
aTurn *= -1.f;
}
// Forward/ backward movement
aForward += aBaseY;
// Handle walking.
HandleWalking();
// check for turn locking
if (bLockTurnUntilRelease)
{
if (RawJoyLookRight != 0)
{
aTurn = 0.f;
if (AutoUnlockTurnTime > 0.f)
{
AutoUnlockTurnTime -= DeltaTime;
if (AutoUnlockTurnTime < 0.f)
{
bLockTurnUntilRelease = FALSE;
}
}
}
else
{
bLockTurnUntilRelease = FALSE;
}
}
// ignore move input
// Do not clear RawJoy flags, as we still want to be able to read input.
if( IsMoveInputIgnored() )
{
aForward = 0.f;
aStrafe = 0.f;
aUp = 0.f;
}
// ignore look input
// Do not clear RawJoy flags, as we still want to be able to read input.
if( IsLookInputIgnored() )
{
aTurn = 0.f;
aLookup = 0.f;
}
}
function CatchDoubleClickInput()
{
if (!IsMoveInputIgnored())
{
bEdgeForward = (bWasForward ^^ (aBaseY > 0));
bEdgeBack = (bWasBack ^^ (aBaseY < 0));
bEdgeLeft = (bWasLeft ^^ (aStrafe < 0));
bEdgeRight = (bWasRight ^^ (aStrafe > 0));
bWasForward = (aBaseY > 0);
bWasBack = (aBaseY < 0);
bWasLeft = (aStrafe < 0);
bWasRight = (aStrafe > 0);
}
}
// check for double click move
function Actor.EDoubleClickDir CheckForDoubleClickMove(float DeltaTime)
{
local Actor.EDoubleClickDir DoubleClickMove, OldDoubleClick;
if ( DoubleClickDir == DCLICK_Active )
DoubleClickMove = DCLICK_Active;
else
DoubleClickMove = DCLICK_None;
if (DoubleClickTime > 0.0)
{
if ( DoubleClickDir == DCLICK_Active )
{
if ( (Pawn != None) && (Pawn.Physics == PHYS_Walking) )
{
DoubleClickTimer = 0;
DoubleClickDir = DCLICK_Done;
}
}
else if ( DoubleClickDir != DCLICK_Done )
{
OldDoubleClick = DoubleClickDir;
DoubleClickDir = DCLICK_None;
if (bEdgeForward && bWasForward)
DoubleClickDir = DCLICK_Forward;
else if (bEdgeBack && bWasBack)
DoubleClickDir = DCLICK_Back;
else if (bEdgeLeft && bWasLeft)
DoubleClickDir = DCLICK_Left;
else if (bEdgeRight && bWasRight)
DoubleClickDir = DCLICK_Right;
if ( DoubleClickDir == DCLICK_None)
DoubleClickDir = OldDoubleClick;
else if ( DoubleClickDir != OldDoubleClick )
DoubleClickTimer = DoubleClickTime + 0.5 * DeltaTime;
else
DoubleClickMove = DoubleClickDir;
}
if (DoubleClickDir == DCLICK_Done)
{
DoubleClickTimer = FMin(DoubleClickTimer-DeltaTime,0);
if (DoubleClickTimer < -0.35)
{
DoubleClickDir = DCLICK_None;
DoubleClickTimer = DoubleClickTime;
}
}
else if ((DoubleClickDir != DCLICK_None) && (DoubleClickDir != DCLICK_Active))
{
DoubleClickTimer -= DeltaTime;
if (DoubleClickTimer < 0)
{
DoubleClickDir = DCLICK_None;
DoubleClickTimer = DoubleClickTime;
}
}
}
return DoubleClickMove;
}
/**
* Iterates through all InputRequests on the PlayerController and
* checks to see if a new input has been matched, or if the entire
* match sequence should be reset.
*
* @param DeltaTime - time since last tick
*/
final function ProcessInputMatching(float DeltaTime)
{
local float Value;
local int i,MatchIdx;
local bool bMatch;
// iterate through each request,
for (i = 0; i < InputRequests.Length; i++)
{
// if we have a valid match idx
if (InputRequests[i].MatchIdx >= 0 &&
InputRequests[i].MatchIdx < InputRequests[i].Inputs.Length)
{
if (InputRequests[i].MatchActor == None)
{
InputRequests[i].MatchActor = Outer;
}
MatchIdx = InputRequests[i].MatchIdx;
// if we've exceeded the delta,
// ignore the delta for the first match
if (MatchIdx != 0 &&
InputRequests[i].Inputs[MatchIdx].TimeDelta > 0.f &&
WorldInfo.TimeSeconds - InputRequests[i].LastMatchTime >= InputRequests[i].Inputs[MatchIdx].TimeDelta)
{
// reset this match
InputRequests[i].LastMatchTime = 0.f;
InputRequests[i].MatchIdx = 0;
// fire off the cancel event
if (InputRequests[i].FailedFuncName != 'None')
{
InputRequests[i].MatchActor.SetTimer(0.01f, false, InputRequests[i].FailedFuncName );
}
}
else
{
// grab the current input value of the matching type
Value = 0.f;
switch (InputRequests[i].Inputs[MatchIdx].Type)
{
case IT_XAxis:
Value = aStrafe;
break;
case IT_YAxis:
Value = aBaseY;
break;
}
// check to see if this matches
switch (InputRequests[i].Inputs[MatchIdx].Action)
{
case IMA_GreaterThan:
bMatch = Value >= InputRequests[i].Inputs[MatchIdx].Value;
break;
case IMA_LessThan:
bMatch = Value <= InputRequests[i].Inputs[MatchIdx].Value;
break;
}
if (bMatch)
{
// mark it as matched
InputRequests[i].LastMatchTime = WorldInfo.TimeSeconds;
InputRequests[i].MatchIdx++;
// check to see if we've matched all inputs
if (InputRequests[i].MatchIdx >= InputRequests[i].Inputs.Length)
{
if (InputRequests[i].MatchDelegate != None)
{
InputMatchDelegate = InputRequests[i].MatchDelegate;
InputMatchDelegate();
}
// fire off the event
if (InputRequests[i].MatchFuncName != 'None')
{
InputRequests[i].MatchActor.SetTimer(0.01f,false,InputRequests[i].MatchFuncName);
}
// reset this match
InputRequests[i].LastMatchTime = 0.f;
InputRequests[i].MatchIdx = 0;
// as well as all others
}
}
}
}
}
}
//*************************************************************************************
// Normal gameplay execs
// Type the name of the exec function at the console to execute it
exec function Jump()
{
if ( WorldInfo.Pauser == PlayerReplicationInfo )
SetPause( False );
else
bPressedJump = true;
}
exec function SmartJump()
{
Jump();
}
//*************************************************************************************
// Mouse smoothing
exec function ClearSmoothing()
{
local int i;
for ( i=0; i<2; i++ )
{
//`Log(i$" zerotime "$zerotime[i]$" smoothedmouse "$SmoothedMouse[i]);
ZeroTime[i] = 0;
SmoothedMouse[i] = 0;
}
//`Log("MouseSamplingTotal "$MouseSamplingTotal$" MouseSamples "$MouseSamples);
MouseSamplingTotal = Default.MouseSamplingTotal;
MouseSamples = Default.MouseSamples;
}
/** SmoothMouse()
Smooth mouse movement, because mouse sampling doesn't match up with tick time.
* @note: if we got sample event for zero mouse samples (so we
didn't have to guess whether a 0 was caused by no sample occuring during the tick (at high frame rates) or because the mouse actually stopped)
* @param: aMouse is the mouse axis movement received from DirectInput
* @param: DeltaTime is the tick time
* @param: SampleCount is the number of mouse samples received from DirectInput
* @param: Index is 0 for X axis, 1 for Y axis
* @return the smoothed mouse axis movement
*/
function float SmoothMouse(float aMouse, float DeltaTime, out byte SampleCount, int Index)
{
local float MouseSamplingTime;
if (DeltaTime < 0.25)
{
MouseSamplingTime = MouseSamplingTotal/MouseSamples;
if ( aMouse == 0 )
{
// no mouse movement received
ZeroTime[Index] += DeltaTime;
if ( ZeroTime[Index] < MouseSamplingTime )
{
// zero mouse movement is possibly because less than the mouse sampling interval has passed
aMouse = SmoothedMouse[Index] * DeltaTime/MouseSamplingTime;
}
else
{
SmoothedMouse[Index] = 0;
}
}
else
{
ZeroTime[Index] = 0;
if ( SmoothedMouse[Index] != 0 )
{
// this isn't the first tick with non-zero mouse movement
if ( DeltaTime < MouseSamplingTime * (SampleCount + 1) )
{
// smooth mouse movement so samples/tick is constant
aMouse = aMouse * DeltaTime/(MouseSamplingTime * SampleCount);
}
else
{
// fewer samples, so going slow
// use number of samples we should have had for sample count
SampleCount = DeltaTime/MouseSamplingTime;
}
}
SmoothedMouse[Index] = aMouse/SampleCount;
}
}
else
{
// if we had an abnormally long frame, clear everything so it doesn't distort the results
ClearSmoothing();
}
SampleCount = 0;
return aMouse;
}
/**
* The player controller will call this function directly after creating the input system
*/
native function InitInputSystem();
/**
* Called via replication to tell the Client to Init it's input system
*/
function ClientInitInputSystem();
/**
* The player controll will call this function directly before traveling
*/
function PreClientTravel( string PendingURL, ETravelType TravelType, bool bIsSeamlessTravel)
{
}
defaultproperties
{
MouseSamplingTotal=+0.0083
MouseSamples=1
}