2022-11-09 09:48:22 +03:00
|
|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
|
|
//
|
|
|
|
// Purpose:
|
|
|
|
//
|
|
|
|
// $Workfile: $
|
|
|
|
// $Date: $
|
|
|
|
//
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// $Log: $
|
|
|
|
//
|
|
|
|
// $NoKeywords: $
|
|
|
|
//=============================================================================//
|
|
|
|
#if !defined( IPREDICTION_H )
|
|
|
|
#define IPREDICTION_H
|
|
|
|
#ifdef _WIN32
|
|
|
|
#pragma once
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#include "sdk/interface.h"
|
|
|
|
#include "sdk/vector.h" // Solely to get at define for QAngle
|
|
|
|
|
|
|
|
|
|
|
|
class IMoveHelper;
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: Engine interface into client side prediction system
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
abstract_class IPrediction
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
virtual ~IPrediction(void) {};
|
|
|
|
|
|
|
|
virtual void Init(void) = 0;
|
|
|
|
virtual void Shutdown(void) = 0;
|
|
|
|
|
|
|
|
// Run prediction
|
|
|
|
virtual void Update
|
|
|
|
(
|
|
|
|
int startframe, // World update ( un-modded ) most recently received
|
|
|
|
bool validframe, // Is frame data valid
|
|
|
|
int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded)
|
|
|
|
int outgoing_command // Last command (most recent) sent to server (un-modded)
|
|
|
|
) = 0;
|
|
|
|
|
|
|
|
// We are about to get a network update from the server. We know the update #, so we can pull any
|
|
|
|
// data purely predicted on the client side and transfer it to the new from data state.
|
|
|
|
virtual void PreEntityPacketReceived(int commands_acknowledged, int current_world_update_packet) = 0;
|
|
|
|
virtual void PostEntityPacketReceived(void) = 0;
|
|
|
|
virtual void PostNetworkDataReceived(int commands_acknowledged) = 0;
|
|
|
|
|
|
|
|
virtual void OnReceivedUncompressedPacket(void) = 0;
|
|
|
|
|
|
|
|
// The engine needs to be able to access a few predicted values
|
|
|
|
virtual void GetViewOrigin(Vector& org) = 0;
|
|
|
|
virtual void SetViewOrigin(Vector& org) = 0;
|
|
|
|
virtual void GetViewAngles(QAngle& ang) = 0;
|
|
|
|
virtual void SetViewAngles(QAngle& ang) = 0;
|
|
|
|
virtual void GetLocalViewAngles(QAngle& ang) = 0;
|
|
|
|
virtual void SetLocalViewAngles(QAngle& ang) = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
extern IPrediction* g_pClientSidePrediction;
|
|
|
|
|
|
|
|
#define VCLIENT_PREDICTION_INTERFACE_VERSION "VClientPrediction001"
|
|
|
|
|
|
|
|
//
|
|
|
|
/*
|
|
|
|
class CBaseEntity;
|
|
|
|
typedef CBaseEntity C_BaseEntity;
|
|
|
|
typedef CBaseEntity CBasePlayer;
|
|
|
|
typedef CBaseEntity C_BasePlayer;
|
|
|
|
typedef CBaseEntity CCSPlayer;
|
|
|
|
typedef CBaseEntity C_CSPlayer;
|
|
|
|
typedef CBaseEntity C_BaseCombatCharacter;
|
|
|
|
typedef CBaseEntity CBaseCombatCharacter;
|
|
|
|
*/
|
|
|
|
|
|
|
|
class CMoveData;
|
|
|
|
class IMoveHelper;
|
|
|
|
class CPDumpPanel;
|
|
|
|
struct typedescription_t;
|
|
|
|
|
|
|
|
//#pragma pack(push, 1)
|
|
|
|
//#pragma pack(pop)
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: Implements prediction in the client .dll
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
class CPrediction : public IPrediction
|
|
|
|
{
|
|
|
|
// Construction
|
|
|
|
public:
|
|
|
|
DECLARE_CLASS_GAMEROOT(CPrediction, IPrediction);
|
|
|
|
|
|
|
|
CPrediction(void);
|
|
|
|
virtual ~CPrediction(void);
|
|
|
|
|
|
|
|
virtual void Init(void);
|
|
|
|
virtual void Shutdown(void);
|
|
|
|
|
|
|
|
// Implement IPrediction
|
|
|
|
public:
|
|
|
|
|
|
|
|
virtual void Update
|
|
|
|
(
|
|
|
|
int startframe, // World update ( un-modded ) most recently received
|
|
|
|
bool validframe, // Is frame data valid
|
|
|
|
int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded)
|
|
|
|
int outgoing_command // Last command (most recent) sent to server (un-modded)
|
|
|
|
);
|
|
|
|
|
|
|
|
virtual void PreEntityPacketReceived(int commands_acknowledged, int current_world_update_packet);
|
|
|
|
virtual void PostEntityPacketReceived(void);
|
|
|
|
virtual void PostNetworkDataReceived(int commands_acknowledged);
|
|
|
|
virtual void OnReceivedUncompressedPacket(void);
|
|
|
|
// The engine needs to be able to access a few predicted values
|
|
|
|
virtual void GetViewOrigin(Vector& org);
|
|
|
|
virtual void SetViewOrigin(Vector& org);
|
|
|
|
virtual void GetViewAngles(QAngle& ang);
|
|
|
|
virtual void SetViewAngles(QAngle& ang);
|
|
|
|
|
|
|
|
virtual void GetLocalViewAngles(QAngle& ang);
|
|
|
|
virtual void SetLocalViewAngles(QAngle& ang);
|
|
|
|
|
|
|
|
virtual bool InPrediction(void) const;
|
|
|
|
virtual bool IsFirstTimePredicted(void) const;
|
|
|
|
virtual int GetLastAcknowledgedCommandNumber(void)const;
|
|
|
|
|
|
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
|
|
virtual int GetIncomingPacketNumber(void) const;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
float GetIdealPitch(int nSlot) const
|
|
|
|
{
|
|
|
|
if (nSlot == -1)
|
|
|
|
{
|
|
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
return 0.f;// m_Split[nSlot].m_flIdealPitch;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void CheckMovingGround(C_BasePlayer* player, double frametime);
|
|
|
|
|
|
|
|
virtual void RunCommand(C_BasePlayer* player, CUserCmd* ucmd, IMoveHelper* moveHelper);
|
|
|
|
|
|
|
|
// Internal
|
|
|
|
public: //dylan changed from protected
|
|
|
|
virtual void SetupMove(C_BasePlayer* player, CUserCmd* ucmd, IMoveHelper* pHelper, CMoveData* move);
|
|
|
|
virtual void FinishMove(C_BasePlayer* player, CUserCmd* ucmd, CMoveData* move);
|
|
|
|
virtual void SetIdealPitch(int nSlot, C_BasePlayer* player, const Vector& origin, const QAngle& angles, const Vector& viewheight);
|
|
|
|
|
|
|
|
void CheckError(int nSlot, C_BasePlayer* player, int commands_acknowledged);
|
|
|
|
|
|
|
|
// Called before and after any movement processing
|
|
|
|
void StartCommand(C_BasePlayer* player, CUserCmd* cmd);
|
|
|
|
void FinishCommand(C_BasePlayer* player);
|
|
|
|
|
|
|
|
// Helpers to call pre and post think for player, and to call think if a think function is set
|
|
|
|
void RunPreThink(C_BasePlayer* player);
|
|
|
|
void RunThink(C_BasePlayer* ent, double frametime);
|
|
|
|
void RunPostThink(C_BasePlayer* player);
|
|
|
|
|
|
|
|
void _Update_New
|
|
|
|
(
|
|
|
|
int nSlot,
|
|
|
|
bool received_new_world_update,
|
|
|
|
bool validframe, // Is frame data valid
|
|
|
|
int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded)
|
|
|
|
int outgoing_command // Last command (most recent) sent to server (un-modded)
|
|
|
|
);
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void _Update
|
|
|
|
(
|
|
|
|
int nSlot,
|
|
|
|
bool received_new_world_update,
|
|
|
|
bool validframe, // Is frame data valid
|
|
|
|
int incoming_acknowledged, // Last command acknowledged to have been run by server (un-modded)
|
|
|
|
int outgoing_command // Last command (most recent) sent to server (un-modded)
|
|
|
|
);
|
|
|
|
|
|
|
|
// Actually does the prediction work, returns false if an error occurred
|
|
|
|
bool PerformPrediction(int nSlot, C_BasePlayer* localPlayer, bool received_new_world_update, int incoming_acknowledged, int outgoing_command);
|
|
|
|
|
|
|
|
void ShiftIntermediateDataForward(int nSlot, int slots_to_remove, int previous_last_slot);
|
|
|
|
void ShiftFirstPredictedIntermediateDataForward(int nSlot, int acknowledged);
|
|
|
|
void RestoreEntityToPredictedFrame(int nSlot, int predicted_frame);
|
|
|
|
int ComputeFirstCommandToExecute(int nSlot, bool received_new_world_update, int incoming_acknowledged, int outgoing_command);
|
|
|
|
int ComputeFirstCommandToExecute_New(CBaseEntity* pPlayer, int nSlot, bool received_new_world_update, int incoming_acknowledged, int outgoing_command);
|
|
|
|
|
|
|
|
void DumpEntity(C_BaseEntity* ent, int commands_acknowledged);
|
|
|
|
|
|
|
|
void ShutdownPredictables(void);
|
|
|
|
void ReinitPredictables(void);
|
|
|
|
|
|
|
|
void RemoveStalePredictedEntities(int nSlot, int last_command_packet);
|
|
|
|
void RestoreOriginalEntityState(int nSlot);
|
|
|
|
void RunSimulation(int current_command, float curtime, CUserCmd* cmd, C_BasePlayer* LocalPlayer);
|
|
|
|
void Untouch(int nSlot);
|
|
|
|
void StorePredictionResults(int nSlot, int predicted_frame);
|
|
|
|
bool ShouldDumpEntity(C_BaseEntity* ent);
|
|
|
|
|
|
|
|
void SmoothViewOnMovingPlatform(C_BasePlayer* pPlayer, Vector& offset);
|
|
|
|
|
|
|
|
#if !defined( NO_ENTITY_PREDICTION )
|
|
|
|
// Data
|
|
|
|
public:
|
|
|
|
// Last object the player was standing on
|
|
|
|
CHandle< C_BaseEntity > m_hLastGround; //0x4
|
|
|
|
bool m_bInPrediction; //0x8
|
|
|
|
bool m_bFirstTimePredicted; //0x9
|
|
|
|
bool m_bEnginePaused; //0x0A
|
|
|
|
bool m_bOldCLPredictValue; //0x0B
|
|
|
|
int m_nPreviousStartFrame; //0x0C
|
|
|
|
int m_nIncomingPacketNumber; //0x10
|
|
|
|
float m_flLastServerWorldTimeStamp; //0x14
|
|
|
|
// Last network origin for local player
|
|
|
|
|
|
|
|
#pragma pack(push, 1)
|
|
|
|
struct Split_t
|
|
|
|
{
|
|
|
|
Split_t() //note: incomplete
|
|
|
|
{
|
|
|
|
m_bFirstTimePredicted = false;
|
|
|
|
m_nCommandsPredicted = 0;
|
|
|
|
m_nServerCommandsAcknowledged = 0;
|
|
|
|
m_bPreviousAckHadErrors = false;
|
|
|
|
//m_flIdealPitch = 0.0f;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool m_bFirstTimePredicted; //0x18
|
|
|
|
char pad[3];
|
|
|
|
int m_nCommandsPredicted; //0x1C
|
|
|
|
int m_nServerCommandsAcknowledged; //0x20 set in PostNetworkDataReceived
|
|
|
|
int m_bPreviousAckHadErrors; //0x24 set in PostNetworkDataReceived
|
|
|
|
int pad2; //0x28
|
|
|
|
int m_nIncomingAcknowledged; //0x2C
|
|
|
|
char m_bUnknown; //0x30 set in PostNetworkDataReceived
|
|
|
|
char pad3[3]; //0x31
|
|
|
|
|
|
|
|
CUtlVector<EHANDLE> m_vecPredictionHandles; //0x34
|
|
|
|
bool m_bUnknown2;
|
|
|
|
char pad4[3];
|
|
|
|
//char pad4[12]; //0x34
|
|
|
|
//int pad5; //0x40 set in PostNetworkDataReceived
|
|
|
|
//int pad6[2]; //0x44
|
|
|
|
|
|
|
|
//end 0x4C
|
|
|
|
};//size 0x34 bytes
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
Split_t m_Split[1]; //0x18 //MAX_SPLITSCREEN_PLAYERS
|
|
|
|
IGlobalVarsBase m_SavedVars; //0x4C
|
|
|
|
bool m_bPlayerOriginTypedescriptionSearched;
|
|
|
|
CUtlVector< const typedescription_t* > m_PlayerOriginTypeDescription; // A vector in cases where the .x, .y, and .z are separately listed
|
|
|
|
|
|
|
|
CPDumpPanel* m_pPDumpPanel;
|
|
|
|
|
|
|
|
#endif
|
2022-11-13 14:56:18 +03:00
|
|
|
|
|
|
|
|
|
|
|
bool InPrediction_v() {
|
|
|
|
typedef bool(__thiscall* o_in_prediction)(void*);
|
|
|
|
return getvfunc<o_in_prediction>(this, 10)(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RunCommand_v(C_BaseEntity* player, CUserCmd* cmd, IMoveHelper* helper) {
|
|
|
|
typedef void(__thiscall* o_run_command)(void*, C_BaseEntity*, CUserCmd*, IMoveHelper*);
|
|
|
|
return getvfunc<o_run_command>(this, 19)(this, player, cmd, helper);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetupMove_v(C_BaseEntity* player, CUserCmd* cmd, IMoveHelper* helper, void* data) {
|
|
|
|
typedef void(__thiscall* o_setup_move)(void*, C_BaseEntity*, CUserCmd*, IMoveHelper*, void*);
|
|
|
|
return getvfunc<o_setup_move>(this, 20)(this, player, cmd, helper, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FinishMove_v(C_BaseEntity* player, CUserCmd* cmd, void* data) {
|
|
|
|
typedef void(__thiscall* o_finish_move)(void*, C_BaseEntity*, CUserCmd*, void*);
|
|
|
|
return getvfunc<o_finish_move>(this, 21)(this, player, cmd, data);
|
|
|
|
}
|
2022-11-09 09:48:22 +03:00
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // IPREDICTION_H
|