mastercomfig / tf2-patches

Team Fortress 2, but with a lot of fixes, QoL improvements and performance optimizations!
Other
221 stars 27 forks source link

Port spec_lerpto from CS:GO #625

Closed Ashetf2 closed 1 year ago

Ashetf2 commented 2 years ago

Description

spec_lerpto is a command in CS:GO that lerps the camera from one point to other. Porting this to TF2 would be a nice touch for content creators to create cinematic cameras in TF2.

My knowledge in programing is limited, but from what I've been investigating, my conclusions are: According to the CS:GO code, spec_lerpto is defined in game\client\cstrike15\clientmode_csnormal.cpp, game\server\player.cpp, and engine\hltvclient.cpp

The function that defines this command in player.cpp is

    else if ( stricmp( cmd, "spec_lerpto" ) == 0 )
    {
        if ( !sv_cheats->GetBool() && (IsAlive())/* || (pPlayer->GetObserverMode() != OBS_MODE_ROAMING && pPlayer->GetObserverMode() != OBS_MODE_FIXED)*/ )
            return false;

        if ( args.ArgC() < 7 )
        {
            ClientPrint( this, HUD_PRINTCONSOLE, "Usage:  spec_lerpto x y z pitch yaw lerptime\n");
            return false;
        }

        Vector oldorigin = GetAbsOrigin();
        Vector newpos;
        newpos.x = clamp( atof(args[1]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
        newpos.y = clamp( atof(args[2]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
        newpos.z = clamp( atof(args[3]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );

        QAngle oldang = GetAbsAngles();
        QAngle newang;
        newang.x = clamp( atof(args[4]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
        newang.y = clamp( atof(args[5]), MIN_COORD_FLOAT, MAX_COORD_FLOAT );
        newang.z = oldang.z;

        // have to clear the observer target before we set the mode to roaming, otherwise it pops our position to the target
        m_hObserverTarget.Set( NULL ); 
        SetObserverMode( OBS_MODE_ROAMING );
        m_iFOV.Set( GetDefaultFOV() );

        SpecLerptoPosition( newpos, newang, clamp( atof(args[7]), MIN_COORD_FLOAT, MAX_COORD_FLOAT ) );

        CBasePlayer *target = UTIL_PlayerByIndex( atoi(args[6]) );
        if ( target )
        {
            m_hObserverTarget.Set( target ); 
            IGameEvent *event = gameeventmanager->CreateEvent( "spec_target_updated" );
            if ( event )
            {
                event->SetInt("userid", GetUserID() );
                gameeventmanager->FireEventClientSide( event );
            }
        }

        return true;
    }

Several of the functions and variables used in this are already defined, and some other aren't.

  1. SpecLerptoPosition isn't in TF2. It is defined in CS:GO as:

player.cpp

void CBasePlayer::SpecLerptoPosition( const Vector &origin, const QAngle &angles, float flTime )
{
    if ( m_iObserverMode != OBS_MODE_ROAMING && m_iObserverMode != OBS_MODE_FIXED )
        return;

    m_bIsSpecLerping = true;

    m_vecSpecLerpOldPos = GetAbsOrigin();
    m_angSpecLerpOldAng = LocalEyeAngles();

    m_vecSpecLerpIdealPos = origin;
    m_angSpecLerpIdealAng = angles;

    m_flSpecLerpTime = flTime;
    m_flSpecLerpEndTime = gpGlobals->curtime + flTime;
}
  1. OBS_MODE_ROAMING in m_iObserverMode doesn't output anything in TF2. In CS:GO:

player.cpp

        case OBS_MODE_ROAMING :
            SetFOV( this, 0 );  // Reset FOV
            SetObserverTarget( m_hObserverTarget );
            SetViewOffset( vec3_origin );
            SetMoveType( MOVETYPE_OBSERVER );
            break;
  1. void C_HLTVCamera::CalcRoamingView and C_HLTVCamera::CalcFixedView in game/client/hltvcamera.cpp have more checks for if ( m_bIsSpecLerping ) in CS:GO. It would be necessary in CalcRoamingView to uncomment //fov = m_flFOV; and comment the next line, since it uses a csgo only command ("fov_cs_debug").

    ̶A̶l̶s̶o̶,̶ ̶I̶'̶m̶ ̶n̶o̶t̶ ̶s̶u̶r̶e̶ ̶w̶h̶a̶t̶ ̶c̶o̶u̶l̶d̶ ̶b̶e̶ ̶t̶h̶e̶ ̶c̶o̶u̶n̶t̶e̶r̶p̶a̶r̶t̶ ̶o̶f̶ ̶c̶l̶i̶e̶n̶t̶m̶o̶d̶e̶̶c̶s̶n̶o̶r̶m̶a̶l̶.̶c̶p̶p̶ ̶i̶n̶ ̶T̶F̶2̶.̶ ̶I̶ ̶d̶o̶n̶'̶t̶ ̶t̶h̶i̶n̶k̶ ̶i̶t̶ ̶i̶s̶ ̶c̶s̶t̶r̶i̶k̶e̶\̶c̶l̶i̶e̶n̶t̶m̶o̶d̶e̶̶c̶s̶n̶o̶r̶m̶a̶l̶.̶c̶p̶p̶

EDIT: The counterpart of clientmode_csnormal.cpp for TF2 would be game\client\tf\clientmode_tf.cpp. Both files share this function: void ClientModeCSNormal::OnScreenshotRequested( ScreenshotRequested_t *pParam )

I'll update this when I do more research.

Checklist

Screenshots

https://user-images.githubusercontent.com/63692647/200708534-5f4dd85f-4ea3-4b90-97aa-85e13e53dc9d.mp4

Alternatives

  1. Camera lerp can be done with demo smoothing, though it is limited to demos. See: https://www.youtube.com/watch?v=X_Db_THGSD8. Maybe the code can be reutilized
  2. Don't :(
Ashetf2 commented 1 year ago

The function bool ClientModeCSNormal::GetIdealCameraPosForPlayer( int playerindex ) in clientmode_csnormal seems important (and contains spec_lerpto too)

getchoo commented 1 year ago

set lerp to 0

Ashetf2 commented 1 year ago

if ( m_bIsSpecLerping ) from void CBasePlayer::CheckObserverSettings() in player.cpp checks the following functions: m_bIsSpecLerping, m_vecSpecLerpIdealPos, m_angSpecLerpIdealAng, m_flSpecLerpEndTime, m_flSpecLerpTime. They all appear in:

game\client\hltvcamera.cpp,game\client\hltvcamera.h, game\server\player.cpp, game\server\player.h and game\shared\baseplayer_shared.cpp

Edit: They may not be important after all

Ashetf2 commented 1 year ago

I expect that with VScript something similar or even better can be achieved. See: https://github.com/samisalreadytaken/keyframes. Closing