Merge pull request #7369 from dobrykafe/pr-demo-extract-chat

Add new tool `demo_extract_chat`
This commit is contained in:
Dennis Felsing 2023-10-25 22:53:32 +00:00 committed by GitHub
commit ee543af004
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 247 additions and 0 deletions

View file

@ -2630,6 +2630,7 @@ if(TOOLS)
config_retrieve.cpp
config_store.cpp
crapnet.cpp
demo_extract_chat.cpp
dilate.cpp
dummy_map.cpp
map_convert_07.cpp
@ -2999,6 +3000,7 @@ if(TOOLS)
set(TARGET_TOOLS
config_retrieve
config_store
demo_extract_chat
dilate
map_convert_07
map_diff

View file

@ -0,0 +1,245 @@
#include <base/logger.h>
#include <base/system.h>
#include <engine/client.h>
#include <game/client/gameclient.h>
static const char *TOOL_NAME = "demo_extract_chat";
class CClientSnapshotHandler
{
public:
struct CClientData
{
char m_aName[MAX_NAME_LENGTH];
};
CClientData m_aClients[MAX_CLIENTS];
CSnapshotStorage::CHolder m_aDemoSnapshotHolders[IClient::NUM_SNAPSHOT_TYPES];
char m_aaaDemoSnapshotData[IClient::NUM_SNAPSHOT_TYPES][2][CSnapshot::MAX_SIZE];
CSnapshotStorage::CHolder *m_apSnapshots[IClient::NUM_SNAPSHOT_TYPES];
CClientSnapshotHandler() :
m_aClients(), m_aDemoSnapshotHolders()
{
mem_zero(m_aaaDemoSnapshotData, sizeof(m_aaaDemoSnapshotData));
for(int SnapshotType = 0; SnapshotType < IClient::NUM_SNAPSHOT_TYPES; SnapshotType++)
{
m_apSnapshots[SnapshotType] = &m_aDemoSnapshotHolders[SnapshotType];
m_apSnapshots[SnapshotType]->m_pSnap = (CSnapshot *)&m_aaaDemoSnapshotData[SnapshotType][0];
m_apSnapshots[SnapshotType]->m_pAltSnap = (CSnapshot *)&m_aaaDemoSnapshotData[SnapshotType][1];
m_apSnapshots[SnapshotType]->m_SnapSize = 0;
m_apSnapshots[SnapshotType]->m_AltSnapSize = 0;
m_apSnapshots[SnapshotType]->m_Tick = -1;
}
}
int UnpackAndValidateSnapshot(CSnapshot *pFrom, CSnapshot *pTo)
{
CUnpacker Unpacker;
CSnapshotBuilder Builder;
Builder.Init();
CNetObjHandler NetObjHandler;
int Num = pFrom->NumItems();
for(int Index = 0; Index < Num; Index++)
{
const CSnapshotItem *pFromItem = pFrom->GetItem(Index);
const int FromItemSize = pFrom->GetItemSize(Index);
const int ItemType = pFrom->GetItemType(Index);
const void *pData = pFromItem->Data();
Unpacker.Reset(pData, FromItemSize);
void *pRawObj = NetObjHandler.SecureUnpackObj(ItemType, &Unpacker);
if(!pRawObj)
continue;
const int ItemSize = NetObjHandler.GetUnpackedObjSize(ItemType);
void *pObj = Builder.NewItem(pFromItem->Type(), pFromItem->ID(), ItemSize);
if(!pObj)
return -4;
mem_copy(pObj, pRawObj, ItemSize);
}
return Builder.Finish(pTo);
}
int SnapNumItems(int SnapID)
{
dbg_assert(SnapID >= 0 && SnapID < IClient::NUM_SNAPSHOT_TYPES, "invalid SnapID");
if(!m_apSnapshots[SnapID])
return 0;
return m_apSnapshots[SnapID]->m_pAltSnap->NumItems();
}
void *SnapGetItem(int SnapID, int Index, IClient::CSnapItem *pItem)
{
dbg_assert(SnapID >= 0 && SnapID < IClient::NUM_SNAPSHOT_TYPES, "invalid SnapID");
const CSnapshotItem *pSnapshotItem = m_apSnapshots[SnapID]->m_pAltSnap->GetItem(Index);
pItem->m_DataSize = m_apSnapshots[SnapID]->m_pAltSnap->GetItemSize(Index);
pItem->m_Type = m_apSnapshots[SnapID]->m_pAltSnap->GetItemType(Index);
pItem->m_ID = pSnapshotItem->ID();
return (void *)pSnapshotItem->Data();
}
void OnNewSnapshot()
{
int Num = SnapNumItems(IClient::SNAP_CURRENT);
for(int i = 0; i < Num; i++)
{
IClient::CSnapItem Item;
const void *pData = SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
if(Item.m_Type == NETOBJTYPE_CLIENTINFO)
{
const CNetObj_ClientInfo *pInfo = (const CNetObj_ClientInfo *)pData;
int ClientID = Item.m_ID;
if(ClientID < MAX_CLIENTS)
{
CClientData *pClient = &m_aClients[ClientID];
IntsToStr(&pInfo->m_Name0, 4, pClient->m_aName);
}
}
}
}
void OnDemoPlayerSnapshot(void *pData, int Size)
{
unsigned char aAltSnapBuffer[CSnapshot::MAX_SIZE];
CSnapshot *pAltSnapBuffer = (CSnapshot *)aAltSnapBuffer;
const int AltSnapSize = UnpackAndValidateSnapshot((CSnapshot *)pData, pAltSnapBuffer);
if(AltSnapSize < 0)
return;
std::swap(m_apSnapshots[IClient::SNAP_PREV], m_apSnapshots[IClient::SNAP_CURRENT]);
mem_copy(m_apSnapshots[IClient::SNAP_CURRENT]->m_pSnap, pData, Size);
mem_copy(m_apSnapshots[IClient::SNAP_CURRENT]->m_pAltSnap, pAltSnapBuffer, AltSnapSize);
OnNewSnapshot();
}
};
class CDemoPlayerMessageListener : public CDemoPlayer::IListener
{
public:
CDemoPlayer *m_pDemoPlayer;
CClientSnapshotHandler *m_pClientSnapshotHandler;
void OnDemoPlayerSnapshot(void *pData, int Size) override
{
m_pClientSnapshotHandler->OnDemoPlayerSnapshot(pData, Size);
}
void OnDemoPlayerMessage(void *pData, int Size) override
{
CUnpacker Unpacker;
Unpacker.Reset(pData, Size);
CMsgPacker Packer(NETMSG_EX, true);
int Msg;
bool Sys;
CUuid Uuid;
int Result = UnpackMessageID(&Msg, &Sys, &Uuid, &Unpacker, &Packer);
if(Result == UNPACKMESSAGE_ERROR)
return;
if(!Sys)
{
CNetObjHandler NetObjHandler;
void *pRawMsg = NetObjHandler.SecureUnpackMsg(Msg, &Unpacker);
if(!pRawMsg)
return;
if(Msg == NETMSGTYPE_SV_CHAT)
{
CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg;
if(pMsg->m_ClientID > -1 && m_pClientSnapshotHandler->m_aClients[pMsg->m_ClientID].m_aName[0] == '\0')
return;
const char *Prefix = pMsg->m_Team > 1 ? "whisper" : (pMsg->m_Team ? "teamchat" : "chat");
if(pMsg->m_ClientID < 0)
{
printf("%s: *** %s\n", Prefix, pMsg->m_pMessage);
return;
}
if(pMsg->m_Team == 2) // WHISPER SEND
printf("%s: -> %s: %s\n", Prefix, m_pClientSnapshotHandler->m_aClients[pMsg->m_ClientID].m_aName, pMsg->m_pMessage);
else if(pMsg->m_Team == 3) // WHISPER RECEIVE
printf("%s: <- %s: %s\n", Prefix, m_pClientSnapshotHandler->m_aClients[pMsg->m_ClientID].m_aName, pMsg->m_pMessage);
else
printf("%s: %s: %s\n", Prefix, m_pClientSnapshotHandler->m_aClients[pMsg->m_ClientID].m_aName, pMsg->m_pMessage);
}
else if(Msg == NETMSGTYPE_SV_BROADCAST)
{
CNetMsg_Sv_Broadcast *pMsg = (CNetMsg_Sv_Broadcast *)pRawMsg;
char aBroadcast[1024];
while((pMsg->m_pMessage = str_next_token(pMsg->m_pMessage, "\n", aBroadcast, sizeof(aBroadcast))))
{
if(aBroadcast[0] != '\0')
{
printf("broadcast: %s\n", aBroadcast);
}
}
}
}
}
};
int Process(const char *pDemoFilePath, IStorage *pStorage)
{
CSnapshotDelta DemoSnapshotDelta;
CDemoPlayer DemoPlayer(&DemoSnapshotDelta, false);
if(DemoPlayer.Load(pStorage, nullptr, pDemoFilePath, IStorage::TYPE_ALL_OR_ABSOLUTE) == -1)
{
dbg_msg(TOOL_NAME, "Demo file '%s' failed to load: %s", pDemoFilePath, DemoPlayer.ErrorMessage());
return -1;
}
CClientSnapshotHandler Handler;
CDemoPlayerMessageListener Listener;
Listener.m_pDemoPlayer = &DemoPlayer;
Listener.m_pClientSnapshotHandler = &Handler;
DemoPlayer.SetListener(&Listener);
const CDemoPlayer::CPlaybackInfo *pInfo = DemoPlayer.Info();
CNetBase::Init();
DemoPlayer.Play();
while(DemoPlayer.IsPlaying())
{
DemoPlayer.Update(false);
if(pInfo->m_Info.m_Paused)
break;
}
DemoPlayer.Stop();
return 0;
}
int main(int argc, const char *argv[])
{
IStorage *pStorage = CreateLocalStorage();
if(!pStorage)
{
dbg_msg(TOOL_NAME, "Error loading storage");
return -1;
}
CCmdlineFix CmdlineFix(&argc, &argv);
log_set_global_logger_default();
if(argc != 2)
{
dbg_msg(TOOL_NAME, "Usage: %s [demo_filename]", TOOL_NAME);
return -1;
}
return Process(argv[1], pStorage);
}