UNTESTED! Switch to ke::LinkedList<ke::AString> for PrintfBuffer.
Switch from OnGameFrame to FramAction. Fix compiling on Episode1 by essentially disabling the feature.
This commit is contained in:
parent
68e5c00f48
commit
f1ca3e8c7f
@ -95,9 +95,10 @@ SH_DECL_EXTERN0_void(ConCommand, Dispatch, SH_NOATTRIB, false);
|
|||||||
#endif
|
#endif
|
||||||
SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, const char *);
|
SH_DECL_HOOK2_void(IVEngineServer, ClientPrintf, SH_NOATTRIB, 0, edict_t *, const char *);
|
||||||
|
|
||||||
static void FrameHook(bool simulating)
|
static void PrintfBuffer_FrameAction(void *data)
|
||||||
{
|
{
|
||||||
g_Players.OnGameFrame();
|
int client = (int)(intptr_t)data;
|
||||||
|
g_Players.OnPrintfFrameAction(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConCommand *maxplayersCmd = NULL;
|
ConCommand *maxplayersCmd = NULL;
|
||||||
@ -212,12 +213,10 @@ void PlayerManager::OnSourceModAllInitialized()
|
|||||||
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
|
SH_ADD_HOOK(ConCommand, Dispatch, pCmd, SH_STATIC(CmdMaxplayersCallback), true);
|
||||||
maxplayersCmd = pCmd;
|
maxplayersCmd = pCmd;
|
||||||
}
|
}
|
||||||
g_SourceMod.AddGameFrameHook(&FrameHook);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerManager::OnSourceModShutdown()
|
void PlayerManager::OnSourceModShutdown()
|
||||||
{
|
{
|
||||||
g_SourceMod.RemoveGameFrameHook(&FrameHook);
|
|
||||||
SH_REMOVE_HOOK(IServerGameClients, ClientConnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientConnect), false);
|
SH_REMOVE_HOOK(IServerGameClients, ClientConnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientConnect), false);
|
||||||
SH_REMOVE_HOOK(IServerGameClients, ClientConnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientConnect_Post), true);
|
SH_REMOVE_HOOK(IServerGameClients, ClientConnect, serverClients, SH_MEMBER(this, &PlayerManager::OnClientConnect_Post), true);
|
||||||
SH_REMOVE_HOOK(IServerGameClients, ClientPutInServer, serverClients, SH_MEMBER(this, &PlayerManager::OnClientPutInServer), true);
|
SH_REMOVE_HOOK(IServerGameClients, ClientPutInServer, serverClients, SH_MEMBER(this, &PlayerManager::OnClientPutInServer), true);
|
||||||
@ -857,143 +856,80 @@ void PlayerManager::OnClientDisconnect_Post(edict_t *pEntity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CPrintfBuffer */
|
|
||||||
CPrintfBuffer::CPrintfBuffer(size_t MaxLength)
|
|
||||||
{
|
|
||||||
m_pFirstChunk = NULL;
|
|
||||||
m_pLastChunk = NULL;
|
|
||||||
m_MaxLength = MaxLength;
|
|
||||||
m_Length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CPrintfBuffer::Append(const char *pString, size_t Length)
|
|
||||||
{
|
|
||||||
if(Length <= 0 || Length >= 1023)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if(m_Length >= m_MaxLength)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CChunk *pChunk = new CChunk();
|
|
||||||
pChunk->m_pMessage = strdup(pString);
|
|
||||||
pChunk->m_pMem = pChunk->m_pMessage;
|
|
||||||
pChunk->m_Length = Length;
|
|
||||||
pChunk->m_pNext = NULL;
|
|
||||||
|
|
||||||
if(m_pLastChunk)
|
|
||||||
m_pLastChunk->m_pNext = pChunk;
|
|
||||||
else
|
|
||||||
m_pFirstChunk = m_pLastChunk = pChunk;
|
|
||||||
|
|
||||||
m_pLastChunk = pChunk;
|
|
||||||
m_Length += Length;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const CPrintfBuffer::CChunk *CPrintfBuffer::Get()
|
|
||||||
{
|
|
||||||
return m_pFirstChunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CPrintfBuffer::Consumed(size_t Length)
|
|
||||||
{
|
|
||||||
if(Length <= 0 || !m_pFirstChunk)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(Length > m_pFirstChunk->m_Length)
|
|
||||||
Length = m_pFirstChunk->m_Length;
|
|
||||||
|
|
||||||
m_pFirstChunk->m_Length -= Length;
|
|
||||||
|
|
||||||
if(m_pFirstChunk->m_Length == 0)
|
|
||||||
{
|
|
||||||
free(m_pFirstChunk->m_pMem);
|
|
||||||
|
|
||||||
if(m_pFirstChunk == m_pLastChunk)
|
|
||||||
{
|
|
||||||
delete m_pFirstChunk;
|
|
||||||
m_pFirstChunk = m_pLastChunk = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CChunk *pTmp = m_pFirstChunk;
|
|
||||||
m_pFirstChunk = m_pFirstChunk->m_pNext;
|
|
||||||
delete pTmp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_pFirstChunk->m_pMessage += Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Length -= Length;
|
|
||||||
}
|
|
||||||
/* CPrintfBuffer */
|
|
||||||
|
|
||||||
void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
void PlayerManager::OnClientPrintf(edict_t *pEdict, const char *szMsg)
|
||||||
{
|
{
|
||||||
int client = IndexOfEdict(pEdict);
|
int client = IndexOfEdict(pEdict);
|
||||||
|
|
||||||
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
|
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
|
||||||
if(pNetChan == NULL)
|
if (pNetChan == NULL)
|
||||||
return;
|
RETURN_META(MRES_IGNORED);
|
||||||
|
|
||||||
CPrintfBuffer *pPrintfBuffer = &m_Players[client].m_PrintfBuffer;
|
|
||||||
|
|
||||||
size_t nMsgLen = strlen(szMsg);
|
size_t nMsgLen = strlen(szMsg);
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false);
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
|
int nNumBitsWritten = 0;
|
||||||
|
#else
|
||||||
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
|
#endif
|
||||||
|
|
||||||
// 2048 = SVC_Print buffersize (-1 for \0)
|
const int NETMSG_TYPE_BITS = 6; // SVC_Print overhead for netmsg type
|
||||||
// 6 = NETMSG_TYPE_BITS, +1 for \0
|
const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
|
||||||
if(pPrintfBuffer->m_StopSend || (nNumBitsWritten + 6) / 8 + nMsgLen + 1 >= 2048)
|
|
||||||
|
// enqueue msgs if we'd overflow the SVC_Print buffer
|
||||||
|
if (m_Players[client].m_PrintfStop || (nNumBitsWritten + NETMSG_TYPE_BITS) / 8 + nMsgLen >= SVC_Print_BufferSize)
|
||||||
{
|
{
|
||||||
// Don't send any more messages for this player until the buffer is empty.
|
// Don't send any more messages for this player until the buffer is empty.
|
||||||
pPrintfBuffer->m_StopSend = true;
|
// Queue up a gameframe hook to empty the buffer (if we haven't already)
|
||||||
|
if(!m_Players[client].m_PrintfStop)
|
||||||
|
g_pSM->AddFrameAction(PrintfBuffer_FrameAction, (void *)(intptr_t)client);
|
||||||
|
|
||||||
|
m_Players[client].m_PrintfStop = true;
|
||||||
|
|
||||||
|
m_Players[client].m_PrintfBuffer.append(szMsg);
|
||||||
|
|
||||||
pPrintfBuffer->Append(szMsg, nMsgLen);
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SH_CALL(engine, &IVEngineServer::ClientPrintf)(pEdict, szMsg);
|
RETURN_META(MRES_IGNORED);
|
||||||
|
|
||||||
RETURN_META(MRES_SUPERCEDE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerManager::OnGameFrame()
|
void PlayerManager::OnPrintfFrameAction(int client)
|
||||||
{
|
{
|
||||||
for(int client = 1; client <= m_maxClients; client++)
|
CPlayer *pPlayer = &m_Players[client];
|
||||||
|
if (!pPlayer->IsInGame())
|
||||||
|
return;
|
||||||
|
|
||||||
|
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
|
||||||
|
if (pNetChan == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ke::LinkedList<ke::AString>::iterator iter = m_Players[client].m_PrintfBuffer.begin();
|
||||||
|
while (iter != m_Players[client].m_PrintfBuffer.end())
|
||||||
{
|
{
|
||||||
CPlayer *pPlayer = &m_Players[client];
|
int nMsgLen = (*iter).length();
|
||||||
if(!pPlayer->IsInGame())
|
#if SOURCE_ENGINE == SE_EPISODEONE
|
||||||
continue;
|
int nNumBitsWritten = 0;
|
||||||
|
#else
|
||||||
|
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false); // SVC_Print uses unreliable netchan
|
||||||
|
#endif
|
||||||
|
|
||||||
INetChannel *pNetChan = static_cast<INetChannel *>(engine->GetPlayerNetInfo(client));
|
const int NETMSG_TYPE_BITS = 6; // SVC_Print overhead for netmsg type
|
||||||
if(pNetChan == NULL)
|
const int SVC_Print_BufferSize = 2048 - 1; // -1 for terminating \0
|
||||||
continue;
|
|
||||||
|
|
||||||
CPrintfBuffer *pPrintfBuffer = &pPlayer->m_PrintfBuffer;
|
// stop if we'd overflow the SVC_Print buffer
|
||||||
|
if((nNumBitsWritten + NETMSG_TYPE_BITS) / 8 + nMsgLen >= SVC_Print_BufferSize)
|
||||||
|
break;
|
||||||
|
|
||||||
const CPrintfBuffer::CChunk *pChunk;
|
SH_CALL(engine, &IVEngineServer::ClientPrintf)(pPlayer->m_pEdict, (*iter).chars());
|
||||||
while((pChunk = pPrintfBuffer->Get()))
|
|
||||||
{
|
|
||||||
int nMsgLen = pChunk->m_Length;
|
|
||||||
int nNumBitsWritten = pNetChan->GetNumBitsWritten(false);
|
|
||||||
|
|
||||||
// 2048 = SVC_Print buffersize (-1 for \0)
|
iter = m_Players[client].m_PrintfBuffer.erase(iter);
|
||||||
// 6 = NETMSG_TYPE_BITS, +1 for \0
|
}
|
||||||
if((nNumBitsWritten + 6) / 8 + nMsgLen + 1 >= 2048)
|
|
||||||
break;
|
|
||||||
|
|
||||||
SH_CALL(engine, &IVEngineServer::ClientPrintf)(pPlayer->m_pEdict, pChunk->m_pMessage);
|
// Buffer is empty, send new messages without enqueuing again.
|
||||||
|
if (iter == m_Players[client].m_PrintfBuffer.end())
|
||||||
pPrintfBuffer->Consumed(nMsgLen);
|
m_Players[client].m_PrintfStop = false;
|
||||||
}
|
else
|
||||||
|
{ // buffer not empty yet, continue processing it on the next gameframe.
|
||||||
// Buffer is empty, send new messages without enqueing again.
|
g_pSM->AddFrameAction(PrintfBuffer_FrameAction, (void *)(intptr_t)client);
|
||||||
if(pChunk == NULL)
|
|
||||||
pPrintfBuffer->m_StopSend = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <sh_list.h>
|
#include <sh_list.h>
|
||||||
#include <sh_vector.h>
|
#include <sh_vector.h>
|
||||||
#include <am-string.h>
|
#include <am-string.h>
|
||||||
|
#include <am-linkedlist.h>
|
||||||
#include "ConVarManager.h"
|
#include "ConVarManager.h"
|
||||||
|
|
||||||
#include <steam/steamclientpublic.h>
|
#include <steam/steamclientpublic.h>
|
||||||
@ -67,32 +68,6 @@ union serial_t
|
|||||||
} bits;
|
} bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPrintfBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct CChunk
|
|
||||||
{
|
|
||||||
void *m_pMem;
|
|
||||||
char *m_pMessage;
|
|
||||||
size_t m_Length;
|
|
||||||
struct CChunk *m_pNext;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool m_StopSend;
|
|
||||||
|
|
||||||
private:
|
|
||||||
CChunk *m_pFirstChunk;
|
|
||||||
CChunk *m_pLastChunk;
|
|
||||||
size_t m_MaxLength;
|
|
||||||
size_t m_Length;
|
|
||||||
|
|
||||||
public:
|
|
||||||
CPrintfBuffer(size_t MaxLength=16384);
|
|
||||||
bool Append(const char *pString, size_t Length);
|
|
||||||
const CChunk *Get();
|
|
||||||
void Consumed(size_t Length);
|
|
||||||
};
|
|
||||||
|
|
||||||
class CPlayer : public IGamePlayer
|
class CPlayer : public IGamePlayer
|
||||||
{
|
{
|
||||||
friend class PlayerManager;
|
friend class PlayerManager;
|
||||||
@ -178,7 +153,8 @@ private:
|
|||||||
#if SOURCE_ENGINE == SE_CSGO
|
#if SOURCE_ENGINE == SE_CSGO
|
||||||
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
QueryCvarCookie_t m_LanguageCookie = InvalidQueryCvarCookie;
|
||||||
#endif
|
#endif
|
||||||
CPrintfBuffer m_PrintfBuffer;
|
ke::LinkedList<ke::AString> m_PrintfBuffer;
|
||||||
|
bool m_PrintfStop = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlayerManager :
|
class PlayerManager :
|
||||||
@ -218,7 +194,7 @@ public:
|
|||||||
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
//void OnClientSettingsChanged_Pre(edict_t *pEntity);
|
||||||
void OnServerHibernationUpdate(bool bHibernating);
|
void OnServerHibernationUpdate(bool bHibernating);
|
||||||
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
void OnClientPrintf(edict_t *pEdict, const char *szMsg);
|
||||||
void OnGameFrame();
|
void OnPrintfFrameAction(int client);
|
||||||
public: //IPlayerManager
|
public: //IPlayerManager
|
||||||
void AddClientListener(IClientListener *listener);
|
void AddClientListener(IClientListener *listener);
|
||||||
void RemoveClientListener(IClientListener *listener);
|
void RemoveClientListener(IClientListener *listener);
|
||||||
|
Loading…
Reference in New Issue
Block a user