[Theatre]: Cleanup (#624)

This commit is contained in:
Edo
2022-12-05 18:45:14 +00:00
committed by GitHub
parent c6cbd7d5c8
commit 210873499c
20 changed files with 216 additions and 111 deletions

View File

@ -58,6 +58,7 @@ namespace Components
Loader::Register(new MapDump());
Loader::Register(new ModList());
Loader::Register(new Network());
Loader::Register(new NetworkDebug());
Loader::Register(new Session());
Loader::Register(new Theatre());
Loader::Register(new ClanTags());

View File

@ -81,6 +81,7 @@ namespace Components
#include "Modules/UIScript.hpp"
#include "Modules/ModList.hpp"
#include "Modules/Network.hpp"
#include "Modules/NetworkDebug.hpp"
#include "Modules/Theatre.hpp"
#include "Modules/QuickPatch.hpp"
#include "Modules/Security.hpp"

View File

@ -94,7 +94,7 @@ namespace Components
++(*Game::com_errorPrintsCount);
MessagePrint(channel, msg);
if (*Game::cls_uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
if (Game::cls->uiStarted != 0 && (*Game::com_fixedConsolePosition == 0))
{
Game::CL_ConsoleFixPosition();
}

View File

@ -263,7 +263,7 @@ namespace Components
{
if (client->reliableAcknowledge < 0)
{
Logger::Print(Game::conChannel_t::CON_CHANNEL_NETWORK, "Negative reliableAcknowledge from {} - cl->reliableSequence is {}, reliableAcknowledge is {}\n",
Logger::Print(Game::CON_CHANNEL_NETWORK, "Negative reliableAcknowledge from {} - cl->reliableSequence is {}, reliableAcknowledge is {}\n",
client->name, client->reliableSequence, client->reliableAcknowledge);
client->reliableAcknowledge = client->reliableSequence;
SendCommand(Game::NS_SERVER, client->header.netchan.remoteAddress, "error", "EXE_LOSTRELIABLECOMMANDS");

View File

@ -0,0 +1,47 @@
#include <STDInclude.hpp>
namespace Components
{
void NetworkDebug::CL_ParseServerMessage_Hk(Game::msg_t* msg)
{
auto file = Game::FS_FOpenFileWrite("badpacket.dat");
if (file)
{
Game::FS_Write(msg->data, msg->cursize, file);
Game::FS_FCloseFile(file);
}
Game::MSG_Discard(msg);
}
void NetworkDebug::CL_ParseBadPacket_f()
{
Game::msg_t msg;
unsigned char* file;
auto fileSize = Game::FS_ReadFile("badpacket.dat", reinterpret_cast<char**>(&file));
if (fileSize < 0)
{
return;
}
ZeroMemory(&msg, sizeof(msg));
msg.cursize = fileSize;
msg.data = file;
Game::MSG_ReadLong(&msg);
Game::MSG_ReadLong(&msg);
assert(0 && "Time to debug this packet, baby!");
Game::CL_ParseServerMessage(0, &msg);
Game::FS_FreeFile(file);
}
NetworkDebug::NetworkDebug()
{
#ifdef _DEBUG
Utils::Hook(0x4AA06A, CL_ParseServerMessage_Hk, HOOK_CALL).install()->quick();
Command::Add("parseBadPacket", CL_ParseBadPacket_f);
#endif
// Backport updates from IW5
Utils::Hook::Set<const char*>(0x45D112, "CL_PacketEvent - ignoring illegible message\n");
}
}

View File

@ -0,0 +1,15 @@
#pragma once
namespace Components
{
class NetworkDebug : public Component
{
public:
NetworkDebug();
private:
static void CL_ParseServerMessage_Hk(Game::msg_t* msg);
static void CL_ParseBadPacket_f();
};
}

View File

@ -2,9 +2,9 @@
namespace Components
{
int Security::MsgReadBitsCompressCheckSV(const char* from, char* to, int size)
int Security::MsgReadBitsCompressCheckSV(const unsigned char* from, unsigned char* to, int size)
{
static char buffer[0x8000];
static unsigned char buffer[0x8000];
if (size > 0x800) return 0;
size = Game::MSG_ReadBitsCompress(from, buffer, size);
@ -15,9 +15,9 @@ namespace Components
return size;
}
int Security::MsgReadBitsCompressCheckCL(const char* from, char* to, int size)
int Security::MsgReadBitsCompressCheckCL(const unsigned char* from, unsigned char* to, int size)
{
static char buffer[0x100000];
static unsigned char buffer[0x100000];
if (size > 0x20000) return 0;
size = Game::MSG_ReadBitsCompress(from, buffer, size);

View File

@ -7,10 +7,10 @@ namespace Components
public:
Security();
private:
static int MsgReadBitsCompressCheckSV(const char* from, char* to, int size);
static int MsgReadBitsCompressCheckCL(const char* from, char* to, int size);
static int MsgReadBitsCompressCheckSV(const unsigned char* from, unsigned char* to, int size);
static int MsgReadBitsCompressCheckCL(const unsigned char* from, unsigned char* to, int size);
private:
static int SVCanReplaceServerCommand(Game::client_t* client, const char* cmd);
static long AtolAdjustPlayerLimit(const char* string);

View File

@ -25,11 +25,11 @@ namespace Components
void Theatre::StoreBaseline(PBYTE snapshotMsg)
{
// Store offset and length
Theatre::BaselineSnapshotMsgLen = *reinterpret_cast<int*>(snapshotMsg + 20);
Theatre::BaselineSnapshotMsgOff = *reinterpret_cast<int*>(snapshotMsg + 28) - 7;
BaselineSnapshotMsgLen = *reinterpret_cast<int*>(snapshotMsg + 20);
BaselineSnapshotMsgOff = *reinterpret_cast<int*>(snapshotMsg + 28) - 7;
// Copy to our snapshot buffer
std::memcpy(Theatre::BaselineSnapshot, *reinterpret_cast<DWORD**>(snapshotMsg + 8), *reinterpret_cast<DWORD*>(snapshotMsg + 20));
std::memcpy(BaselineSnapshot, *reinterpret_cast<DWORD**>(snapshotMsg + 8), *reinterpret_cast<DWORD*>(snapshotMsg + 20));
}
__declspec(naked) void Theatre::BaselineStoreStub()
@ -37,7 +37,7 @@ namespace Components
_asm
{
push edi
call Theatre::StoreBaseline
call StoreBaseline
pop edi
mov edx, 5ABEF5h
@ -48,15 +48,15 @@ namespace Components
void Theatre::WriteBaseline()
{
static unsigned char bufData[131072];
static char cmpData[131072];
static unsigned char cmpData[131072];
Game::msg_t buf;
Game::MSG_Init(&buf, bufData, 131072);
Game::MSG_WriteData(&buf, &Theatre::BaselineSnapshot[Theatre::BaselineSnapshotMsgOff], Theatre::BaselineSnapshotMsgLen - Theatre::BaselineSnapshotMsgOff);
Game::MSG_WriteData(&buf, &BaselineSnapshot[BaselineSnapshotMsgOff], BaselineSnapshotMsgLen - BaselineSnapshotMsgOff);
Game::MSG_WriteByte(&buf, 6);
const auto compressedSize = Game::MSG_WriteBitsCompress(false, reinterpret_cast<char*>(buf.data), cmpData, buf.cursize);
const auto compressedSize = Game::MSG_WriteBitsCompress(false, buf.data, cmpData, buf.cursize);
const auto fileCompressedSize = compressedSize + 4;
int byte8 = 8;
@ -86,7 +86,7 @@ namespace Components
__asm
{
pushad
call Theatre::WriteBaseline
call WriteBaseline
popad
// Restore overwritten operation
@ -161,12 +161,12 @@ namespace Components
{
Game::Com_Printf(channel, message, file);
Theatre::CurrentInfo.name = file;
Theatre::CurrentInfo.mapname = (*Game::sv_mapname)->current.string;
Theatre::CurrentInfo.gametype = (*Game::sv_gametype)->current.string;
Theatre::CurrentInfo.author = Steam::SteamFriends()->GetPersonaName();
Theatre::CurrentInfo.length = Game::Sys_Milliseconds();
std::time(&Theatre::CurrentInfo.timeStamp);
CurrentInfo.name = file;
CurrentInfo.mapname = (*Game::sv_mapname)->current.string;
CurrentInfo.gametype = (*Game::sv_gametype)->current.string;
CurrentInfo.author = Steam::SteamFriends()->GetPersonaName();
CurrentInfo.length = Game::Sys_Milliseconds();
std::time(&CurrentInfo.timeStamp);
}
void Theatre::StopRecordStub(int channel, char* message)
@ -174,17 +174,17 @@ namespace Components
Game::Com_Printf(channel, message);
// Store correct length
Theatre::CurrentInfo.length = Game::Sys_Milliseconds() - Theatre::CurrentInfo.length;
CurrentInfo.length = Game::Sys_Milliseconds() - CurrentInfo.length;
// Write metadata
FileSystem::FileWriter meta(Utils::String::VA("%s.json", Theatre::CurrentInfo.name.data()));
meta.write(nlohmann::json(Theatre::CurrentInfo.to_json()).dump());
FileSystem::FileWriter meta(std::format("{}.json", CurrentInfo.name));
meta.write(nlohmann::json(CurrentInfo.to_json()).dump());
}
void Theatre::LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Theatre::CurrentSelection = 0;
Theatre::Demos.clear();
CurrentSelection = 0;
Demos.clear();
const auto demos = FileSystem::GetFileList("demos/", "dm_13");
@ -198,35 +198,34 @@ namespace Components
try
{
metaObject = nlohmann::json::parse(meta.getBuffer());
DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
demoInfo.author = metaObject["author"].get<std::string>();
demoInfo.gametype = metaObject["gametype"].get<std::string>();
demoInfo.mapname = metaObject["mapname"].get<std::string>();
demoInfo.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>();
demoInfo.timeStamp = _atoi64(timestamp.data());
Demos.push_back(demoInfo);
}
catch (const nlohmann::json::parse_error& ex)
{
Logger::PrintError(Game::CON_CHANNEL_ERROR, "Json Parse Error: {}\n", ex.what());
continue;
}
Theatre::DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
demoInfo.author = metaObject["author"].get<std::string>();
demoInfo.gametype = metaObject["gametype"].get<std::string>();
demoInfo.mapname = metaObject["mapname"].get<std::string>();
demoInfo.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>();
demoInfo.timeStamp = _atoi64(timestamp.data());
Theatre::Demos.push_back(demoInfo);
}
}
// Reverse, latest demo first!
std::ranges::reverse(Theatre::Demos);
std::ranges::reverse(Demos);
}
void Theatre::DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Theatre::CurrentSelection < Theatre::Demos.size())
if (CurrentSelection < Demos.size())
{
Theatre::DemoInfo demoInfo = Theatre::Demos[Theatre::CurrentSelection];
auto demoInfo = Demos.at(CurrentSelection);
Logger::Print("Deleting demo {}...\n", demoInfo.name);
@ -242,31 +241,30 @@ namespace Components
Dvar::Var("ui_demo_date").set("");
// Reload demos
Theatre::LoadDemos(UIScript::Token(), info);
LoadDemos(UIScript::Token(), info);
}
}
void Theatre::PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Theatre::CurrentSelection < Theatre::Demos.size())
if (CurrentSelection < Demos.size())
{
Command::Execute(Utils::String::VA("demo %s", Theatre::Demos[Theatre::CurrentSelection].name.data()), true);
Command::Execute(std::format("demo {}", Demos[CurrentSelection].name), true);
Command::Execute("demoback", false);
}
}
unsigned int Theatre::GetDemoCount()
{
return Theatre::Demos.size();
return Demos.size();
}
// Omit column here
const char* Theatre::GetDemoText(unsigned int item, int /*column*/)
{
if (item < Theatre::Demos.size())
if (item < Demos.size())
{
Theatre::DemoInfo info = Theatre::Demos[item];
auto info = Demos.at(item);
return Utils::String::VA("%s on %s", Game::UI_LocalizeGameType(info.gametype.data()), Game::UI_LocalizeMapName(info.mapname.data()));
}
@ -275,13 +273,13 @@ namespace Components
void Theatre::SelectDemo(unsigned int index)
{
if (index < Theatre::Demos.size())
if (index < Demos.size())
{
Theatre::CurrentSelection = index;
Theatre::DemoInfo info = Theatre::Demos[index];
CurrentSelection = index;
auto info = Demos.at(index);
tm time;
char buffer[1000] = { 0 };
char buffer[1000] = {0};
localtime_s(&time, &info.timeStamp);
asctime_s(buffer, sizeof buffer, &time);
@ -299,7 +297,7 @@ namespace Components
if (Dvar::Var("cl_autoRecord").get<bool>() && !*Game::demoPlaying)
{
std::vector<std::string> files;
std::vector<std::string> demos = FileSystem::GetFileList("demos/", "dm_13");
auto demos = FileSystem::GetFileList("demos/", "dm_13");
for (auto demo : demos)
{
@ -309,9 +307,9 @@ namespace Components
}
}
int numDel = files.size() - Dvar::Var("cl_demosKeep").get<int>();
auto numDel = static_cast<int>(files.size()) - Dvar::Var("cl_demosKeep").get<int>();
for (int i = 0; i < numDel; ++i)
for (auto i = 0; i < numDel; ++i)
{
Logger::Print("Deleting old demo {}\n", files[i]);
FileSystem::_DeleteFile("demos", files[i].data());
@ -326,17 +324,10 @@ namespace Components
void Theatre::MapChangeStub()
{
Theatre::StopRecording();
StopRecording();
Utils::Hook::Call<void()>(0x464A60)();
}
// DANGEROUS, DON'T USE THIS ONE!
void Theatre::MapChangeSVStub(char* a1, char* a2)
{
Theatre::StopRecording();
Utils::Hook::Call<void(char*, char*)>(0x487C50)(a1, a2);
}
void Theatre::StopRecording()
{
if (*Game::demoRecording)
@ -350,30 +341,29 @@ namespace Components
Dvar::Register<bool>("cl_autoRecord", true, Game::DVAR_ARCHIVE, "Automatically record games.");
Dvar::Register<int>("cl_demosKeep", 30, 1, 999, Game::DVAR_ARCHIVE, "How many demos to keep with autorecord.");
Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A85D2, Theatre::RecordGamestateStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5ABE36, Theatre::BaselineStoreStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x5A8630, Theatre::BaselineToFileStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x4CB3EF, Theatre::UISetActiveMenuStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A8E03, Theatre::ServerTimedOutStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x5A8370, GamestateWriteStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A85D2, RecordGamestateStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5ABE36, BaselineStoreStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x5A8630, BaselineToFileStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x4CB3EF, UISetActiveMenuStub, HOOK_JUMP).install()->quick();
Utils::Hook(0x50320E, AdjustTimeDeltaStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A8E03, ServerTimedOutStub, HOOK_JUMP).install()->quick();
// Hook commands to enforce metadata generation
Utils::Hook(0x5A82AE, Theatre::RecordStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A8156, Theatre::StopRecordStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A82AE, RecordStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A8156, StopRecordStub, HOOK_CALL).install()->quick();
// Autorecording
Utils::Hook(0x5A1D6A, Theatre::InitCGameStub, HOOK_CALL).install()->quick();
Utils::Hook(0x4A712A, Theatre::MapChangeStub, HOOK_CALL).install()->quick();
//Utils::Hook(0x5AA91C, Theatre::MapChangeSVStub, HOOK_CALL).install()->quick();
Utils::Hook(0x5A1D6A, InitCGameStub, HOOK_CALL).install()->quick();
Utils::Hook(0x4A712A, MapChangeStub, HOOK_CALL).install()->quick();
// UIScripts
UIScript::Add("loadDemos", Theatre::LoadDemos);
UIScript::Add("launchDemo", Theatre::PlayDemo);
UIScript::Add("deleteDemo", Theatre::DeleteDemo);
UIScript::Add("loadDemos", LoadDemos);
UIScript::Add("launchDemo", PlayDemo);
UIScript::Add("deleteDemo", DeleteDemo);
// Feeder
UIFeeder::Add(10.0f, Theatre::GetDemoCount, Theatre::GetDemoText, Theatre::SelectDemo);
UIFeeder::Add(10.0f, GetDemoCount, GetDemoText, SelectDemo);
// set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps
if (!Dedicated::IsEnabled()) Utils::Hook::Set<const char*>(0x47440B, "mp/defaultStringTable.csv");
@ -381,11 +371,5 @@ namespace Components
// Change font size
Utils::Hook::Set<BYTE>(0x5AC854, 2);
Utils::Hook::Set<BYTE>(0x5AC85A, 2);
// Command::Add("democycle", [] (Command::Params params)
// {
// // Cmd_FollowCycle_f
// Utils::Hook::Call<void(Game::gentity_t*, int)>(0x458ED0)(Game::g_entities, -1);
// });
}
}

View File

@ -62,7 +62,6 @@ namespace Components
static uint32_t InitCGameStub();
static void MapChangeStub();
static void MapChangeSVStub(char* a1, char* a2);
static void RecordStub(int channel, char* message, char* file);
static void StopRecordStub(int channel, char* message);