Initial commit
This commit is contained in:
commit
3dd53cf457
105 changed files with 35670 additions and 0 deletions
445
src/schema/serversideclient.h
Normal file
445
src/schema/serversideclient.h
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
//
|
||||
// Created by Michal Přikryl on 26.06.2025.
|
||||
// Copyright (c) 2025 slynxcz. All rights reserved.
|
||||
//
|
||||
#pragma once
|
||||
|
||||
#include "playerslot.h"
|
||||
#include "steam/steamclientpublic.h"
|
||||
#include "utlstring.h"
|
||||
#include "inetchannel.h"
|
||||
#include "networkbasetypes.pb.h"
|
||||
#include <inetchannel.h>
|
||||
#include <playerslot.h>
|
||||
#include "circularbuffer.h"
|
||||
#include "networksystem/inetworksystem.h"
|
||||
#include "threadtools.h"
|
||||
#include "tier1/netadr.h"
|
||||
#include <entity2/entityidentity.h>
|
||||
#include <networksystem/inetworksystem.h>
|
||||
#include <steam/steamclientpublic.h>
|
||||
#include <tier1/utlstring.h>
|
||||
#include <network_connection.pb.h>
|
||||
#include <netmessages.pb.h>
|
||||
|
||||
namespace
|
||||
TemplatePlugin
|
||||
{
|
||||
class CHLTVServer;
|
||||
class INetMessage;
|
||||
class CNetworkGameServerBase;
|
||||
class CNetworkGameServer;
|
||||
class CFrameSnapshot;
|
||||
|
||||
class CMsg_CVars;
|
||||
class CNETMsg_StringCmd_t;
|
||||
class CNETMsg_Tick_t;
|
||||
class CNETMsg_SpawnGroup_LoadCompleted_t;
|
||||
class CCLCMsg_ClientInfo_t;
|
||||
class CCLCMsg_BaselineAck_t;
|
||||
class CCLCMsg_LoadingProgress_t;
|
||||
class CCLCMsg_SplitPlayerConnect_t;
|
||||
class CCLCMsg_SplitPlayerDisconnect_t;
|
||||
class CCLCMsg_CmdKeyValues_t;
|
||||
class CCLCMsg_Move_t;
|
||||
class CCLCMsg_VoiceData_t;
|
||||
class CCLCMsg_FileCRCCheck_t;
|
||||
class CCLCMsg_RespondCvarValue_t;
|
||||
class NetMessagePacketStart_t;
|
||||
class NetMessagePacketEnd_t;
|
||||
class NetMessageConnectionClosed_t;
|
||||
class NetMessageConnectionCrashed_t;
|
||||
class NetMessageSplitscreenUserChanged_t;
|
||||
|
||||
struct HltvReplayStats_t
|
||||
{
|
||||
enum FailEnum_t
|
||||
{
|
||||
FAILURE_ALREADY_IN_REPLAY,
|
||||
FAILURE_TOO_FREQUENT,
|
||||
FAILURE_NO_FRAME,
|
||||
FAILURE_NO_FRAME2,
|
||||
FAILURE_CANNOT_MATCH_DELAY,
|
||||
FAILURE_FRAME_NOT_READY,
|
||||
NUM_FAILURES
|
||||
};
|
||||
|
||||
uint nClients;
|
||||
uint nStartRequests;
|
||||
uint nSuccessfulStarts;
|
||||
uint nStopRequests;
|
||||
uint nAbortStopRequests;
|
||||
uint nUserCancels;
|
||||
uint nFullReplays;
|
||||
uint nNetAbortReplays;
|
||||
uint nFailedReplays[NUM_FAILURES];
|
||||
}; // sizeof 56
|
||||
COMPILE_TIME_ASSERT(sizeof(HltvReplayStats_t) == 56);
|
||||
|
||||
struct Spike_t
|
||||
{
|
||||
public:
|
||||
CUtlString m_szDesc;
|
||||
int m_nBits;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(Spike_t) == 16);
|
||||
|
||||
class CNetworkStatTrace
|
||||
{
|
||||
public:
|
||||
CUtlVector<Spike_t> m_Records;
|
||||
int m_nMinWarningBytes;
|
||||
int m_nStartBit;
|
||||
int m_nCurBit;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(CNetworkStatTrace) == 40);
|
||||
|
||||
enum CopiedLockState_t : int32
|
||||
{
|
||||
CLS_NOCOPY = 0,
|
||||
CLS_UNLOCKED = 1,
|
||||
CLS_LOCKED_BY_COPYING_THREAD = 2,
|
||||
};
|
||||
|
||||
template <class MUTEX, CopiedLockState_t L = CLS_UNLOCKED>
|
||||
class CCopyableLock : public MUTEX
|
||||
{
|
||||
typedef MUTEX BaseClass;
|
||||
|
||||
public:
|
||||
// ...
|
||||
};
|
||||
|
||||
class CUtlSignaller_Base
|
||||
{
|
||||
public:
|
||||
using Delegate_t = CUtlDelegate<void(CUtlSlot*)>;
|
||||
|
||||
CUtlSignaller_Base(const Delegate_t& other) :
|
||||
m_SlotDeletionDelegate(other)
|
||||
{
|
||||
}
|
||||
|
||||
CUtlSignaller_Base(Delegate_t&& other) :
|
||||
m_SlotDeletionDelegate(Move(other))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
Delegate_t m_SlotDeletionDelegate;
|
||||
};
|
||||
|
||||
class CUtlSlot
|
||||
{
|
||||
public:
|
||||
using MTElement_t = CUtlSignaller_Base*;
|
||||
|
||||
CUtlSlot() :
|
||||
m_ConnectedSignallers(0, 1)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
CCopyableLock<CThreadFastMutex> m_Mutex;
|
||||
CUtlVector<MTElement_t> m_ConnectedSignallers;
|
||||
};
|
||||
|
||||
class CServerSideClientBase : public CUtlSlot, public INetworkChannelNotify,
|
||||
public INetworkMessageProcessingPreFilter
|
||||
{
|
||||
public:
|
||||
virtual ~CServerSideClientBase() = 0;
|
||||
|
||||
public:
|
||||
CPlayerSlot GetPlayerSlot() const { return m_nClientSlot; }
|
||||
CPlayerUserId GetUserID() const { return m_UserID; }
|
||||
CEntityIndex GetEntityIndex() const { return m_nEntityIndex; }
|
||||
CSteamID GetClientSteamID() const { return m_SteamID; }
|
||||
const char* GetClientName() const { return m_Name; }
|
||||
INetChannel* GetNetChannel() const { return m_NetChannel; }
|
||||
const netadr_t* GetRemoteAddress() const { return &m_nAddr.GetAddress(); }
|
||||
CNetworkGameServerBase* GetServer() const { return m_Server; }
|
||||
|
||||
virtual void Connect(int socket, const char* pszName, int nUserID, INetChannel* pNetChannel,
|
||||
uint8 nConnectionTypeFlags,
|
||||
uint32 uChallengeNumber) = 0;
|
||||
// bool bFakePlayer = !nConnectionTypeFlags || (nConnectionTypeFlags & 8) != 0;
|
||||
virtual void Inactivate(const char* pszAddons) = 0;
|
||||
virtual void Reactivate(CPlayerSlot nSlot) = 0;
|
||||
virtual void SetServer(CNetworkGameServer* pNetServer) = 0;
|
||||
virtual void Reconnect() = 0;
|
||||
virtual void Disconnect(ENetworkDisconnectionReason reason, const char* pszInternalReason) = 0;
|
||||
virtual bool CheckConnect() = 0;
|
||||
virtual void Create(CPlayerSlot& nSlot, CSteamID nSteamID, const char* pszName) = 0;
|
||||
virtual void SetRate(int nRate) = 0;
|
||||
virtual void SetUpdateRate(float fUpdateRate) = 0;
|
||||
virtual int GetRate() = 0;
|
||||
|
||||
virtual void Clear() = 0;
|
||||
|
||||
virtual bool ExecuteStringCommand(const CNETMsg_StringCmd_t& msg) = 0;
|
||||
// "false" trigger an anti spam counter to kick a client.
|
||||
virtual bool SendNetMessage(const CNetMessage* pData, NetChannelBufType_t bufType = BUF_DEFAULT) = 0;
|
||||
|
||||
// "Client %d(%s) tried to send a RebroadcastSourceId msg.\n"
|
||||
virtual bool FilterMessage(const CNetMessage* pData, INetChannel* pChannel) = 0;
|
||||
// On Windows, this function is in a separate virtual table
|
||||
|
||||
public:
|
||||
virtual void ClientPrintf(PRINTF_FORMAT_STRING const char*, ...) = 0;
|
||||
|
||||
bool IsConnected() const { return m_nSignonState >= SIGNONSTATE_CONNECTED; }
|
||||
bool IsInGame() const { return m_nSignonState == SIGNONSTATE_FULL; }
|
||||
bool IsSpawned() const { return m_nSignonState >= SIGNONSTATE_NEW; }
|
||||
bool IsActive() const { return m_nSignonState == SIGNONSTATE_FULL; }
|
||||
virtual bool IsFakeClient() const { return m_bFakePlayer; }
|
||||
bool IsHLTV() const { return m_bIsHLTV; }
|
||||
virtual bool IsHumanPlayer() const { return false; }
|
||||
|
||||
// Is an actual human player or splitscreen player (not a bot and not a HLTV slot)
|
||||
virtual bool IsHearingClient(CPlayerSlot nSlot) const { return false; }
|
||||
virtual bool IsProximityHearingClient() const = 0;
|
||||
virtual bool IsLowViolenceClient() const { return m_bLowViolence; }
|
||||
|
||||
virtual bool IsSplitScreenUser() const { return m_bSplitScreenUser; }
|
||||
|
||||
public: // Message Handlers
|
||||
virtual bool ProcessTick(const CNETMsg_Tick_t& msg) = 0;
|
||||
virtual bool ProcessStringCmd(const CNETMsg_StringCmd_t& msg) = 0;
|
||||
|
||||
public:
|
||||
virtual bool ApplyConVars(const CMsg_CVars& list) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_28() = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessSpawnGroup_LoadCompleted(const CNETMsg_SpawnGroup_LoadCompleted_t& msg) = 0;
|
||||
virtual bool ProcessClientInfo(const CCLCMsg_ClientInfo_t& msg) = 0;
|
||||
virtual bool ProcessBaselineAck(const CCLCMsg_BaselineAck_t& msg) = 0;
|
||||
virtual bool ProcessLoadingProgress(const CCLCMsg_LoadingProgress_t& msg) = 0;
|
||||
virtual bool ProcessSplitPlayerConnect(const CCLCMsg_SplitPlayerConnect_t& msg) = 0;
|
||||
virtual bool ProcessSplitPlayerDisconnect(const CCLCMsg_SplitPlayerDisconnect_t& msg) = 0;
|
||||
virtual bool ProcessCmdKeyValues(const CCLCMsg_CmdKeyValues_t& msg) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_36() = 0;
|
||||
virtual bool unk_37() = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessMove(const CCLCMsg_Move_t& msg) = 0;
|
||||
virtual bool ProcessVoiceData(const CCLCMsg_VoiceData_t& msg) = 0;
|
||||
virtual bool ProcessRespondCvarValue(const CCLCMsg_RespondCvarValue_t& msg) = 0;
|
||||
|
||||
virtual bool ProcessPacketStart(const NetMessagePacketStart_t& msg) = 0;
|
||||
virtual bool ProcessPacketEnd(const NetMessagePacketEnd_t& msg) = 0;
|
||||
virtual bool ProcessConnectionClosed(const NetMessageConnectionClosed_t& msg) = 0;
|
||||
virtual bool ProcessConnectionCrashed(const NetMessageConnectionCrashed_t& msg) = 0;
|
||||
|
||||
public:
|
||||
virtual bool ProcessChangeSplitscreenUser(const NetMessageSplitscreenUserChanged_t& msg) = 0;
|
||||
|
||||
private:
|
||||
virtual bool unk_47() = 0;
|
||||
virtual bool unk_48() = 0;
|
||||
virtual bool unk_49() = 0;
|
||||
|
||||
public:
|
||||
virtual void ConnectionStart(INetChannel* pNetChannel) = 0;
|
||||
|
||||
private: // SpawnGroup something.
|
||||
virtual void unk_51() = 0;
|
||||
virtual void unk_52() = 0;
|
||||
|
||||
public:
|
||||
virtual void ExecuteDelayedCall(void*) = 0;
|
||||
|
||||
virtual bool UpdateAcknowledgedFramecount(int tick) = 0;
|
||||
|
||||
void ForceFullUpdate()
|
||||
{
|
||||
// For some reason, it doesn't work.
|
||||
// UpdateAcknowledgedFramecount(-1);
|
||||
m_nDeltaTick = -1;
|
||||
}
|
||||
|
||||
virtual bool ShouldSendMessages() = 0;
|
||||
virtual void UpdateSendState() = 0;
|
||||
|
||||
virtual const CMsgPlayerInfo& GetPlayerInfo() const { return m_playerInfo; }
|
||||
|
||||
virtual void UpdateUserSettings() = 0;
|
||||
virtual void ResetUserSettings() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_60() = 0;
|
||||
|
||||
public:
|
||||
virtual void SendSignonData() = 0;
|
||||
virtual void SpawnPlayer() = 0;
|
||||
virtual void ActivatePlayer() = 0;
|
||||
|
||||
virtual void SetName(const char* name) = 0;
|
||||
virtual void SetUserCVar(const char* cvar, const char* value) = 0;
|
||||
|
||||
SignonState_t GetSignonState() const { return m_nSignonState; }
|
||||
|
||||
virtual void FreeBaselines() = 0;
|
||||
|
||||
bool IsFullyAuthenticated(void) { return m_bFullyAuthenticated; }
|
||||
void SetFullyAuthenticated(void) { m_bFullyAuthenticated = true; }
|
||||
|
||||
virtual CServerSideClientBase* GetSplitScreenOwner() { return m_pAttachedTo; }
|
||||
|
||||
virtual int GetNumPlayers() = 0;
|
||||
|
||||
virtual void ShouldReceiveStringTableUserData() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_70(CPlayerSlot nSlot) = 0;
|
||||
virtual void unk_71() = 0;
|
||||
virtual void unk_72() = 0;
|
||||
|
||||
public:
|
||||
virtual int GetHltvLastSendTick() = 0;
|
||||
|
||||
private:
|
||||
virtual void unk_74() = 0;
|
||||
virtual void unk_75() = 0;
|
||||
virtual void unk_76() = 0;
|
||||
|
||||
public:
|
||||
virtual void Await() = 0;
|
||||
|
||||
virtual void MarkToKick() = 0;
|
||||
virtual void UnmarkToKick() = 0;
|
||||
|
||||
virtual bool ProcessSignonStateMsg(int state) = 0;
|
||||
virtual void PerformDisconnection(ENetworkDisconnectionReason reason) = 0;
|
||||
|
||||
public:
|
||||
CUtlString m_UserIDString;
|
||||
CUtlString m_Name;
|
||||
CPlayerSlot m_nClientSlot;
|
||||
CEntityIndex m_nEntityIndex;
|
||||
CNetworkGameServerBase* m_Server;
|
||||
INetChannel* m_NetChannel;
|
||||
// CServerSideClientBase::Connect( name='%s', userid=%d, fake=%d, connectiontypeflags=%d, chan->addr=%s )
|
||||
uint8 m_nConnectionTypeFlags;
|
||||
uint8 m_nAsyncDisconnectFlags; // check in Disconnect function, 1 add to queue, 2 disconnect now
|
||||
bool m_bMarkedToKick;
|
||||
SignonState_t m_nSignonState;
|
||||
bool m_bSplitScreenUser;
|
||||
bool m_bSplitAllowFastDisconnect;
|
||||
int m_nSplitScreenPlayerSlot;
|
||||
CServerSideClientBase* m_SplitScreenUsers[4];
|
||||
CServerSideClientBase* m_pAttachedTo;
|
||||
bool m_bSplitPlayerDisconnecting;
|
||||
int m_nDisconnectionTypeFlags;
|
||||
bool m_bFakePlayer;
|
||||
bool m_bSendingSnapshot;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad162[0x6];
|
||||
|
||||
public:
|
||||
CPlayerUserId m_UserID = -1;
|
||||
bool m_bReceivedPacket; // true, if client received a packet after the last send packet
|
||||
CSteamID m_SteamID;
|
||||
CSteamID m_DisconnectedSteamID;
|
||||
CSteamID m_AuthTicketSteamID; // Auth ticket
|
||||
CSteamID m_nFriendsID;
|
||||
ns_address m_nAddr;
|
||||
ns_address m_nAddr2;
|
||||
KeyValues* m_ConVars;
|
||||
bool m_bUnk0;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad281[0x28];
|
||||
|
||||
public:
|
||||
bool m_bConVarsChanged;
|
||||
bool m_bIsHLTV;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad323[0xD];
|
||||
|
||||
public:
|
||||
uint32 m_nSendtableCRC;
|
||||
uint32 m_uChallengeNumber;
|
||||
int m_nSignonTick;
|
||||
int m_nDeltaTick;
|
||||
int m_UnkVariable3;
|
||||
int m_nStringTableAckTick;
|
||||
int m_UnkVariable4;
|
||||
CFrameSnapshot* m_pLastSnapshot; // last send snapshot
|
||||
CUtlVector<void*> m_vecLoadedSpawnGroups;
|
||||
CMsgPlayerInfo m_playerInfo;
|
||||
CFrameSnapshot* m_pBaseline;
|
||||
int m_nBaselineUpdateTick;
|
||||
CBitVec<MAX_EDICTS> m_BaselinesSent;
|
||||
int m_nBaselineUsed; // 0/1 toggling flag, singaling client what baseline to use
|
||||
int m_nLoadingProgress; // 0..100 progress, only valid during loading
|
||||
|
||||
// This is used when we send out a nodelta packet to put the client in a state where we wait
|
||||
// until we get an ack from them on this packet.
|
||||
// This is for 3 reasons:
|
||||
// 1. A client requesting a nodelta packet means they're screwed so no point in deluging them with data.
|
||||
// Better to send the uncompressed data at a slow rate until we hear back from them (if at all).
|
||||
// 2. Since the nodelta packet deletes all client entities, we can't ever delta from a packet previous to it.
|
||||
// 3. It can eat up a lot of CPU on the server to keep building nodelta packets while waiting for
|
||||
// a client to get back on its feet.
|
||||
int m_nForceWaitForTick = -1;
|
||||
|
||||
CCircularBuffer m_UnkBuffer = {1024};
|
||||
bool m_bLowViolence = false; // true if client is in low-violence mode (L4D server needs to know)
|
||||
bool m_bSomethingWithAddressType = true;
|
||||
bool m_bFullyAuthenticated = false;
|
||||
bool m_bUnk1 = false;
|
||||
int m_nUnk;
|
||||
|
||||
// The datagram is written to after every frame, but only cleared
|
||||
// when it is sent out to the client. overflow is tolerated.
|
||||
|
||||
// Time when we should send next world state update ( datagram )
|
||||
float m_fNextMessageTime = 0.0f;
|
||||
float m_fAuthenticatedTime = -1.0f;
|
||||
|
||||
// Default time to wait for next message
|
||||
float m_fSnapshotInterval = 0.0f;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad2572[0x8];
|
||||
[[maybe_unused]] char m_packetmsg[0x15C]; // CSVCMsg_PacketEntities_t
|
||||
#ifdef __linux__
|
||||
[[maybe_unused]] char pad2928[0x8];
|
||||
#endif
|
||||
|
||||
public:
|
||||
CNetworkStatTrace m_Trace;
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad2976[0x8];
|
||||
|
||||
public:
|
||||
// SV: Player %s kicked for too many failed console commands
|
||||
int m_spamCommandsCount = 0; // if the value is greater than 16, the player will be kicked with reason 39
|
||||
int m_unknown = 0;
|
||||
double m_lastExecutedCommand = 0.0; // if command executed more than once per second, ++m_spamCommandCount
|
||||
|
||||
private:
|
||||
[[maybe_unused]] char pad3000[0x8];
|
||||
|
||||
public:
|
||||
CCommand* m_pCommand;
|
||||
};
|
||||
#ifdef __linux__
|
||||
COMPILE_TIME_ASSERT(sizeof(CServerSideClientBase) == 3016);
|
||||
#endif
|
||||
|
||||
class CServerSideClient : public CServerSideClientBase
|
||||
{
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue