From 5f6b07205f4a5e68eff917fdb23153c8add90e69 Mon Sep 17 00:00:00 2001 From: maxime1907 <19607336+maxime1907@users.noreply.github.com> Date: Tue, 13 Jul 2021 04:28:55 +0200 Subject: [PATCH] Update --- addons/sourcemod/gamedata/ssf.games.txt | 12 + extension.cpp | 284 +++++++++++++++++++++++- 2 files changed, 292 insertions(+), 4 deletions(-) diff --git a/addons/sourcemod/gamedata/ssf.games.txt b/addons/sourcemod/gamedata/ssf.games.txt index 6112168..0041998 100644 --- a/addons/sourcemod/gamedata/ssf.games.txt +++ b/addons/sourcemod/gamedata/ssf.games.txt @@ -21,6 +21,18 @@ "library" "engine" "linux" "@_ZN11CBaseServer17WriteTempEntitiesEP11CBaseClientP14CFrameSnapshotS3_R8bf_writei" } + + "CGameClient_FillSoundsMessage" + { + "library" "engine" + "linux" "@_ZN11CGameClient17FillSoundsMessageER10SVC_Sounds" + } + + "CGameClient__WriteGameSounds" + { + "library" "engine" + "linux" "@_ZN11CGameClient15WriteGameSoundsER8bf_write" + } } } } diff --git a/extension.cpp b/extension.cpp index f54ab14..31751c7 100644 --- a/extension.cpp +++ b/extension.cpp @@ -37,15 +37,159 @@ #include #include #include +#include class CFrameSnapshot; class CClientFrame; +#define NETMSG_TYPE_BITS 6 // must be 2^NETMSG_TYPE_BITS > SVC_LASTMSG + +#define NET_MAX_PAYLOAD 4000 + +#define svc_Sounds 17 // starts playing sound + +#define DECLARE_BASE_MESSAGE( msgtype ) \ + public: \ + bool ReadFromBuffer( bf_read &buffer ); \ + bool WriteToBuffer( bf_write &buffer ); \ + const char *ToString() const; \ + int GetType() const { return msgtype; } \ + const char *GetName() const { return #msgtype;}\ + +#define DECLARE_SVC_MESSAGE( name ) \ + DECLARE_BASE_MESSAGE( svc_##name ); \ + IServerMessageHandler *m_pMessageHandler;\ + bool Process() { return m_pMessageHandler->Process##name( this ); }\ + +class INetChannelInfo +{ +public: + + enum { + GENERIC = 0, // must be first and is default group + LOCALPLAYER, // bytes for local player entity update + OTHERPLAYERS, // bytes for other players update + ENTITIES, // all other entity bytes + SOUNDS, // game sounds + EVENTS, // event messages + USERMESSAGES, // user messages + ENTMESSAGES, // entity messages + VOICE, // voice data + STRINGTABLE, // a stringtable update + MOVE, // client move cmds + STRINGCMD, // string command + SIGNON, // various signondata + TOTAL, // must be last and is not a real group + }; +}; + +class INetMessage +{ +public: + virtual ~INetMessage() {}; + + // Use these to setup who can hear whose voice. + // Pass in client indices (which are their ent indices - 1). + + virtual void SetNetChannel(INetChannel * netchan) = 0; // netchannel this message is from/for + virtual void SetReliable( bool state ) = 0; // set to true if it's a reliable message + + virtual bool Process( void ) = 0; // calles the recently set handler to process this message + + virtual bool ReadFromBuffer( bf_read &buffer ) = 0; // returns true if parsing was OK + virtual bool WriteToBuffer( bf_write &buffer ) = 0; // returns true if writing was OK + + virtual bool IsReliable( void ) const = 0; // true, if message needs reliable handling + + virtual int GetType( void ) const = 0; // returns module specific header tag eg svc_serverinfo + virtual int GetGroup( void ) const = 0; // returns net message group of this message + virtual const char *GetName( void ) const = 0; // returns network message name, eg "svc_serverinfo" + virtual INetChannel *GetNetChannel( void ) const = 0; + virtual const char *ToString( void ) const = 0; // returns a human readable string about message content +}; + +class CNetMessage : public INetMessage +{ +public: + CNetMessage() { m_bReliable = true; + m_NetChannel = NULL; } + + virtual ~CNetMessage() {}; + + virtual int GetGroup() const { return INetChannelInfo::GENERIC; } + INetChannel *GetNetChannel() const { return m_NetChannel; } + + virtual void SetReliable( bool state) {m_bReliable = state;}; + virtual bool IsReliable() const { return m_bReliable; }; + virtual void SetNetChannel(INetChannel * netchan) { m_NetChannel = netchan; } + virtual bool Process() { Assert( 0 ); return false; }; // no handler set + +protected: + bool m_bReliable; // true if message should be send reliable + INetChannel *m_NetChannel; // netchannel this message is from/for +}; + +class SVC_Sounds : public CNetMessage +{ + DECLARE_SVC_MESSAGE( Sounds ); + + int GetGroup() const { return INetChannelInfo::SOUNDS; } + + SVC_Sounds() : CNetMessage() + { + + } + + ~SVC_Sounds() + { + + } + +public: + + bool m_bReliableSound; + int m_nNumSounds; + int m_nLength; + bf_read m_DataIn; + bf_write m_DataOut; +}; + class CBaseClient : public IGameEventListener2, public IClient { }; +class CGameClient: public CBaseClient +{ +public: + CUtlVector m_Sounds; // game sounds +}; + +bool SVC_Sounds::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + Assert( m_nNumSounds > 0 ); + + if ( m_bReliableSound ) + { + // as single sound message is 32 bytes long maximum + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( m_nLength, 8 ); + } + else + { + // a bunch of unreliable messages + buffer.WriteOneBit( 0 ); + buffer.WriteUBitLong( m_nNumSounds, 8 ); + buffer.WriteUBitLong( m_nLength, 16 ); + } + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + SSF g_SSF; /**< Global singleton for extension's main interface */ SMEXT_LINK(&g_SSF); @@ -55,14 +199,118 @@ CGlobalVars *gpGlobals = NULL; CDetour *g_Detour_CBaseClient__SendSnapshot = NULL; CDetour *g_Detour_CBaseServer__WriteTempEntities = NULL; +CDetour *g_Detour_CGameClient__FillSoundsMessage = NULL; +CDetour *g_Detour_CGameClient__WriteGameSounds = NULL; ConVar *g_SvSSFLog = CreateConVar("sv_ssf_log", "0", FCVAR_NOTIFY, "Log ssf debug print statements."); -ConVar *g_sv_multiplayer_maxtempentities = CreateConVar("sv_multiplayer_maxtempentities", "32"); +ConVar *g_sv_multiplayer_maxtempentities = CreateConVar("sv_multiplayer_maxtempentities", "64"); +ConVar *g_sv_multiplayer_maxsounds = CreateConVar("sv_multiplayer_sounds", "32"); +ConVar *g_sv_sound_discardextraunreliable = CreateConVar( "sv_sound_discardextraunreliable", "1" ); -// ConVar *g_sv_multiplayer_maxsounds = CreateConVar("sv_multiplayer_sounds", "20"); -// ConVar *g_sv_sound_discardextraunreliable = CreateConVar( "sv_sound_discardextraunreliable", "1" ); +int Custom_CGameClient__FillSoundsMessage(CGameClient *pGameClient, SVC_Sounds &msg) +{ + int nMaxSounds = pGameClient->GetServer()->IsMultiplayer() ? g_sv_multiplayer_maxsounds->GetInt() : 255; + int i, count = pGameClient->m_Sounds.Count(); -DETOUR_DECL_MEMBER5(CBaseServer__WriteTempEntities, void, CBaseClient *, client, CFrameSnapshot *, pCurrentSnapshot, CFrameSnapshot *, pLastSnapshot, bf_write, &buf, int, ev_max) + if (g_SvSSFLog->GetBool()) + { + g_pSM->LogMessage(myself, "SSF:CGameClient__FillSoundsMessage maxsounds before: %d, count: %d", nMaxSounds, pGameClient->m_Sounds.Count()); + } + + // Discard events if we have too many to signal with 8 bits + if ( count > nMaxSounds ) + count = nMaxSounds; + + // Nothing to send + if ( !count ) + return 0; + + SoundInfo_t defaultSound; defaultSound.SetDefault(); + SoundInfo_t *pDeltaSound = &defaultSound; + + msg.m_nNumSounds = count; + msg.m_bReliableSound = false; + msg.SetReliable( false ); + + if (g_SvSSFLog->GetBool()) + { + g_pSM->LogMessage(myself, "SSF:CGameClient__FillSoundsMessage getnumbitsleft: %d", msg.m_DataOut.GetNumBitsLeft()); + } + + Assert( msg.m_DataOut.GetNumBitsLeft() > 0 ); + + for ( i = 0 ; i < count; i++ ) + { + SoundInfo_t &sound = pGameClient->m_Sounds[ i ]; + sound.WriteDelta( pDeltaSound, msg.m_DataOut ); + pDeltaSound = &pGameClient->m_Sounds[ i ]; + } + + // remove added events from list + if ( g_sv_sound_discardextraunreliable->GetBool() ) + { + if ( pGameClient->m_Sounds.Count() != count ) + { + DevMsg( 2, "Warning! Dropped %i unreliable sounds for client %s.\n" , pGameClient->m_Sounds.Count() - count, pGameClient->GetClientName() ); + } + pGameClient->m_Sounds.RemoveAll(); + } + else + { + int remove = pGameClient->m_Sounds.Count() - ( count + nMaxSounds ); + if ( remove > 0 ) + { + DevMsg( 2, "Warning! Dropped %i unreliable sounds for client %s.\n" , remove, pGameClient->GetClientName() ); + count+= remove; + } + + if ( count > 0 ) + { + pGameClient->m_Sounds.RemoveMultiple( 0, count ); + } + } + + if (g_SvSSFLog->GetBool()) + { + g_pSM->LogMessage(myself, "SSF:CGameClient__FillSoundsMessage maxsounds after: %d count: %d, NumSounds: %d", nMaxSounds, pGameClient->m_Sounds.Count(), msg.m_nNumSounds); + } + + Assert( pGameClient->m_Sounds.Count() <= nMaxSounds ); // keep ev_max temp ent for next update + + return msg.m_nNumSounds; +} + +DETOUR_DECL_MEMBER1(CGameClient__FillSoundsMessage, int, SVC_Sounds &, msg) +{ + CGameClient *pGameClient = (CGameClient *)this; + + int nResult = Custom_CGameClient__FillSoundsMessage(pGameClient, msg); + + RETURN_META_VALUE(MRES_SUPERCEDE, nResult); +} + +DETOUR_DECL_MEMBER1(CGameClient__WriteGameSounds, void, bf_write, &buf) +{ + CGameClient *pGameClient = (CGameClient *)this; + + if ( pGameClient->m_Sounds.Count() <= 0 ) + return; + + char data[NET_MAX_PAYLOAD]; + SVC_Sounds msg; + msg.m_DataOut.StartWriting( data, sizeof(data) ); + + msg.SetReliable( false ); + int nSoundCount = Custom_CGameClient__FillSoundsMessage( pGameClient, msg ); + msg.WriteToBuffer( buf ); + + // if ( pGameClient->IsTracing() ) + // { + // pGameClient->TraceNetworkData( buf, "Sounds [count=%d]", nSoundCount ); + // } +} + +DETOUR_DECL_MEMBER5(CBaseServer__WriteTempEntities, void, CBaseClient *, client, CFrameSnapshot *, pCurrentSnapshot, CFrameSnapshot *, pLastSnapshot, bf_write &, buf, int, ev_max) { if (!client->IsHLTV() && !client->IsReplay()) { @@ -137,6 +385,22 @@ bool SSF::SDK_OnLoad(char *error, size_t maxlen, bool late) } g_Detour_CBaseServer__WriteTempEntities->EnableDetour(); + g_Detour_CGameClient__FillSoundsMessage = DETOUR_CREATE_MEMBER(CGameClient__FillSoundsMessage, "CGameClient__FillSoundsMessage"); + if(!g_Detour_CGameClient__FillSoundsMessage) + { + snprintf(error, maxlen, "Failed to detour CGameClient__FillSoundsMessage.\n"); + return false; + } + g_Detour_CGameClient__FillSoundsMessage->EnableDetour(); + + g_Detour_CGameClient__WriteGameSounds = DETOUR_CREATE_MEMBER(CGameClient__WriteGameSounds, "CGameClient__WriteGameSounds"); + if(!g_Detour_CGameClient__WriteGameSounds) + { + snprintf(error, maxlen, "Failed to detour CGameClient__WriteGameSounds.\n"); + return false; + } + g_Detour_CGameClient__WriteGameSounds->EnableDetour(); + AutoExecConfig(g_pCVar, true); return true; @@ -156,6 +420,18 @@ void SSF::SDK_OnUnload() g_Detour_CBaseServer__WriteTempEntities = NULL; } + if(g_Detour_CGameClient__FillSoundsMessage) + { + g_Detour_CGameClient__FillSoundsMessage->Destroy(); + g_Detour_CGameClient__FillSoundsMessage = NULL; + } + + if(g_Detour_CGameClient__WriteGameSounds) + { + g_Detour_CGameClient__WriteGameSounds->Destroy(); + g_Detour_CGameClient__WriteGameSounds = NULL; + } + gameconfs->CloseGameConfigFile(g_pGameConf); }