Threater stuff.
This commit is contained in:
parent
0bcbd75787
commit
d28cbd956e
@ -85,8 +85,6 @@ namespace Components
|
|||||||
|
|
||||||
std::string rotation = Dvar::Var("sv_mapRotationCurrent").Get<std::string>();
|
std::string rotation = Dvar::Var("sv_mapRotationCurrent").Get<std::string>();
|
||||||
|
|
||||||
// Ignores " for now, too lazy to implement
|
|
||||||
// TODO: Implement!
|
|
||||||
auto tokens = Utils::Explode(rotation, ' ');
|
auto tokens = Utils::Explode(rotation, ' ');
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (tokens.size() - 1); i += 2)
|
for (unsigned int i = 0; i < (tokens.size() - 1); i += 2)
|
||||||
@ -122,11 +120,6 @@ namespace Components
|
|||||||
Logger::Print("Applying new gametype: %s\n", value.data());
|
Logger::Print("Applying new gametype: %s\n", value.data());
|
||||||
Dvar::Var("g_gametype").Set(value);
|
Dvar::Var("g_gametype").Set(value);
|
||||||
}
|
}
|
||||||
else if (key == "fs_game")
|
|
||||||
{
|
|
||||||
Logger::Print("Applying new mod: %s\n", value.data());
|
|
||||||
Dvar::Var("fs_game").Set(value);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger::Print("Unsupported maprotation key '%s', motherfucker!\n", key.data());
|
Logger::Print("Unsupported maprotation key '%s', motherfucker!\n", key.data());
|
||||||
|
@ -23,6 +23,57 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileSystem::FileWriter::Write(std::string data)
|
||||||
|
{
|
||||||
|
if (this->Handle)
|
||||||
|
{
|
||||||
|
Game::FS_Write(data.data(), data.size(), this->Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::FileWriter::Open()
|
||||||
|
{
|
||||||
|
this->Handle = Game::FS_FOpenFileWrite(this->FilePath.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::FileWriter::Close()
|
||||||
|
{
|
||||||
|
if (this->Handle)
|
||||||
|
{
|
||||||
|
Game::FS_FCloseFile(this->Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> FileSystem::GetFileList(std::string path, std::string extension)
|
||||||
|
{
|
||||||
|
std::vector<std::string> fileList;
|
||||||
|
|
||||||
|
int numFiles = 0;
|
||||||
|
char** files = Game::FS_ListFiles(path.data(), extension.data(), Game::FS_LIST_PURE_ONLY, &numFiles, 0);
|
||||||
|
|
||||||
|
if (files)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < numFiles; i++)
|
||||||
|
{
|
||||||
|
if (files[i])
|
||||||
|
{
|
||||||
|
fileList.push_back(files[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::FS_FreeFileList(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::DeleteFile(std::string folder, std::string file)
|
||||||
|
{
|
||||||
|
char path[MAX_PATH] = { 0 };
|
||||||
|
Game::FS_BuildPathToFile(Dvar::Var("fs_basepath").Get<const char*>(), (char*)0x63D0BB8, Utils::VA("%s/%s", folder.data(), file.data()), (char**)&path);
|
||||||
|
Game::FS_Remove(path);
|
||||||
|
}
|
||||||
|
|
||||||
int FileSystem::ExecIsFSStub(const char* execFilename)
|
int FileSystem::ExecIsFSStub(const char* execFilename)
|
||||||
{
|
{
|
||||||
return !File(execFilename).Exists();
|
return !File(execFilename).Exists();
|
||||||
|
@ -21,9 +21,28 @@ namespace Components
|
|||||||
void Read();
|
void Read();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FileWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileWriter(std::string file) : FilePath(file), Handle(0) { this->Open(); };
|
||||||
|
~FileWriter() { this->Close(); };
|
||||||
|
|
||||||
|
void Write(std::string data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int Handle;
|
||||||
|
std::string FilePath;
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
|
};
|
||||||
|
|
||||||
FileSystem();
|
FileSystem();
|
||||||
const char* GetName() { return "FileSystem"; };
|
const char* GetName() { return "FileSystem"; };
|
||||||
|
|
||||||
|
static std::vector<std::string> GetFileList(std::string path, std::string extension);
|
||||||
|
static void DeleteFile(std::string folder, std::string file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int ExecIsFSStub(const char* execFilename);
|
static int ExecIsFSStub(const char* execFilename);
|
||||||
};
|
};
|
||||||
|
@ -4,14 +4,14 @@ namespace Components
|
|||||||
{
|
{
|
||||||
ServerInfo::Container ServerInfo::PlayerContainer;
|
ServerInfo::Container ServerInfo::PlayerContainer;
|
||||||
|
|
||||||
int ServerInfo::GetPlayerCount()
|
unsigned int ServerInfo::GetPlayerCount()
|
||||||
{
|
{
|
||||||
return ServerInfo::PlayerContainer.PlayerList.size();
|
return ServerInfo::PlayerContainer.PlayerList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ServerInfo::GetPlayerText(int index, int column)
|
const char* ServerInfo::GetPlayerText(unsigned int index, int column)
|
||||||
{
|
{
|
||||||
if ((unsigned int)index < ServerInfo::PlayerContainer.PlayerList.size())
|
if (index < ServerInfo::PlayerContainer.PlayerList.size())
|
||||||
{
|
{
|
||||||
switch (column)
|
switch (column)
|
||||||
{
|
{
|
||||||
@ -32,7 +32,7 @@ namespace Components
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerInfo::SelectPlayer(int index)
|
void ServerInfo::SelectPlayer(unsigned int index)
|
||||||
{
|
{
|
||||||
ServerInfo::PlayerContainer.CurrentPlayer = index;
|
ServerInfo::PlayerContainer.CurrentPlayer = index;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace Components
|
|||||||
std::string Name;
|
std::string Name;
|
||||||
};
|
};
|
||||||
|
|
||||||
int CurrentPlayer;
|
unsigned int CurrentPlayer;
|
||||||
std::vector<Player> PlayerList;
|
std::vector<Player> PlayerList;
|
||||||
Network::Address Target;
|
Network::Address Target;
|
||||||
};
|
};
|
||||||
@ -26,8 +26,8 @@ namespace Components
|
|||||||
|
|
||||||
static void ServerStatus();
|
static void ServerStatus();
|
||||||
|
|
||||||
static int GetPlayerCount();
|
static unsigned int GetPlayerCount();
|
||||||
static const char* GetPlayerText(int index, int column);
|
static const char* GetPlayerText(unsigned int index, int column);
|
||||||
static void SelectPlayer(int index);
|
static void SelectPlayer(unsigned int index);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace Components
|
|||||||
std::vector<ServerList::ServerInfo> ServerList::OfflineList;
|
std::vector<ServerList::ServerInfo> ServerList::OfflineList;
|
||||||
std::vector<ServerList::ServerInfo> ServerList::FavouriteList;
|
std::vector<ServerList::ServerInfo> ServerList::FavouriteList;
|
||||||
|
|
||||||
std::vector<int> ServerList::VisibleList;
|
std::vector<unsigned int> ServerList::VisibleList;
|
||||||
|
|
||||||
std::vector<ServerList::ServerInfo>* ServerList::GetList()
|
std::vector<ServerList::ServerInfo>* ServerList::GetList()
|
||||||
{
|
{
|
||||||
@ -49,12 +49,12 @@ namespace Components
|
|||||||
return (Dvar::Var("ui_netSource").Get<int>() == 1);
|
return (Dvar::Var("ui_netSource").Get<int>() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ServerList::GetServerCount()
|
unsigned int ServerList::GetServerCount()
|
||||||
{
|
{
|
||||||
return (int)ServerList::VisibleList.size();
|
return ServerList::VisibleList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* ServerList::GetServerText(int index, int column)
|
const char* ServerList::GetServerText(unsigned int index, int column)
|
||||||
{
|
{
|
||||||
ServerList::ServerInfo* info = ServerList::GetServer(index);
|
ServerList::ServerInfo* info = ServerList::GetServer(index);
|
||||||
|
|
||||||
@ -121,9 +121,9 @@ namespace Components
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerList::SelectServer(int index)
|
void ServerList::SelectServer(unsigned int index)
|
||||||
{
|
{
|
||||||
ServerList::CurrentServer = (unsigned int)index;
|
ServerList::CurrentServer = index;
|
||||||
|
|
||||||
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
|
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
|
||||||
|
|
||||||
@ -412,8 +412,8 @@ namespace Components
|
|||||||
{
|
{
|
||||||
qsort(ServerList::VisibleList.data(), ServerList::VisibleList.size(), sizeof(int), [] (const void* first, const void* second)
|
qsort(ServerList::VisibleList.data(), ServerList::VisibleList.size(), sizeof(int), [] (const void* first, const void* second)
|
||||||
{
|
{
|
||||||
int server1 = *(int*)first;
|
unsigned int server1 = *(unsigned int*)first;
|
||||||
int server2 = *(int*)second;
|
unsigned int server2 = *(unsigned int*)second;
|
||||||
|
|
||||||
ServerInfo* info1 = nullptr;
|
ServerInfo* info1 = nullptr;
|
||||||
ServerInfo* info2 = nullptr;
|
ServerInfo* info2 = nullptr;
|
||||||
@ -421,8 +421,8 @@ namespace Components
|
|||||||
auto list = ServerList::GetList();
|
auto list = ServerList::GetList();
|
||||||
if (!list) return 0;
|
if (!list) return 0;
|
||||||
|
|
||||||
if (list->size() > (unsigned int)server1) info1 = &(*list)[server1];
|
if (list->size() > server1) info1 = &(*list)[server1];
|
||||||
if (list->size() > (unsigned int)server2) info2 = &(*list)[server2];
|
if (list->size() > server2) info2 = &(*list)[server2];
|
||||||
|
|
||||||
if (!info1) return 1;
|
if (!info1) return 1;
|
||||||
if (!info2) return -1;
|
if (!info2) return -1;
|
||||||
@ -445,14 +445,14 @@ namespace Components
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerList::ServerInfo* ServerList::GetServer(int index)
|
ServerList::ServerInfo* ServerList::GetServer(unsigned int index)
|
||||||
{
|
{
|
||||||
if (ServerList::VisibleList.size() > (unsigned int)index)
|
if (ServerList::VisibleList.size() > index)
|
||||||
{
|
{
|
||||||
auto list = ServerList::GetList();
|
auto list = ServerList::GetList();
|
||||||
if (!list) return nullptr;
|
if (!list) return nullptr;
|
||||||
|
|
||||||
if (list->size() > (unsigned int)ServerList::VisibleList[index])
|
if (list->size() > ServerList::VisibleList[index])
|
||||||
{
|
{
|
||||||
return &(*list)[ServerList::VisibleList[index]];
|
return &(*list)[ServerList::VisibleList[index]];
|
||||||
}
|
}
|
||||||
|
@ -93,10 +93,10 @@ namespace Components
|
|||||||
std::mutex Mutex;
|
std::mutex Mutex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int GetServerCount();
|
static unsigned int GetServerCount();
|
||||||
static const char* GetServerText(int index, int column);
|
static const char* GetServerText(unsigned int index, int column);
|
||||||
static const char* GetServerText(ServerInfo* server, int column);
|
static const char* GetServerText(ServerInfo* server, int column);
|
||||||
static void SelectServer(int index);
|
static void SelectServer(unsigned int index);
|
||||||
|
|
||||||
static void UpdateSource();
|
static void UpdateSource();
|
||||||
static void UpdateGameType();
|
static void UpdateGameType();
|
||||||
@ -108,7 +108,7 @@ namespace Components
|
|||||||
static void LoadFavourties();
|
static void LoadFavourties();
|
||||||
static void StoreFavourite(std::string server);
|
static void StoreFavourite(std::string server);
|
||||||
|
|
||||||
static ServerInfo* GetServer(int index);
|
static ServerInfo* GetServer(unsigned int index);
|
||||||
static std::vector<ServerInfo>* GetList();
|
static std::vector<ServerInfo>* GetList();
|
||||||
|
|
||||||
static int SortKey;
|
static int SortKey;
|
||||||
@ -121,6 +121,6 @@ namespace Components
|
|||||||
static std::vector<ServerInfo> OfflineList;
|
static std::vector<ServerInfo> OfflineList;
|
||||||
static std::vector<ServerInfo> FavouriteList;
|
static std::vector<ServerInfo> FavouriteList;
|
||||||
|
|
||||||
static std::vector<int> VisibleList;
|
static std::vector<unsigned int> VisibleList;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
|
Theatre::Container Theatre::DemoContainer;
|
||||||
|
|
||||||
char Theatre::BaselineSnapshot[131072] = { 0 };
|
char Theatre::BaselineSnapshot[131072] = { 0 };
|
||||||
PBYTE Theatre::BaselineSnapshotMsg = 0;
|
PBYTE Theatre::BaselineSnapshotMsg = 0;
|
||||||
int Theatre::BaselineSnapshotMsgLen;
|
int Theatre::BaselineSnapshotMsgLen;
|
||||||
@ -128,18 +130,18 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
void __declspec(naked) Theatre::UISetActiveMenuStub()
|
void __declspec(naked) Theatre::UISetActiveMenuStub()
|
||||||
{
|
|
||||||
if (*Game::demoPlaying == 1)
|
|
||||||
{
|
{
|
||||||
__asm
|
__asm
|
||||||
{
|
{
|
||||||
|
mov eax, Game::demoPlaying
|
||||||
|
mov eax, [eax]
|
||||||
|
test al, al
|
||||||
|
jz continue
|
||||||
|
|
||||||
mov eax, 4CB49Ch
|
mov eax, 4CB49Ch
|
||||||
jmp eax
|
jmp eax
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
__asm
|
continue:
|
||||||
{
|
|
||||||
mov ecx, [esp + 10h]
|
mov ecx, [esp + 10h]
|
||||||
push 10h
|
push 10h
|
||||||
push ecx
|
push ecx
|
||||||
@ -148,6 +150,125 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Theatre::RecordStub(int channel, char* message, char* file)
|
||||||
|
{
|
||||||
|
Game::Com_Printf(channel, message, file);
|
||||||
|
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Name = file;
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Mapname = Dvar::Var("mapname").Get<const char*>();
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Gametype = Dvar::Var("g_gametype").Get<const char*>();
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Author = Steam::SteamFriends()->GetPersonaName();
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Length = Game::Com_Milliseconds();
|
||||||
|
std::time(&Theatre::DemoContainer.CurrentInfo.TimeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theatre::StopRecordStub(int channel, char* message)
|
||||||
|
{
|
||||||
|
Game::Com_Printf(channel, message);
|
||||||
|
|
||||||
|
// Store correct length
|
||||||
|
Theatre::DemoContainer.CurrentInfo.Length = Game::Com_Milliseconds() - Theatre::DemoContainer.CurrentInfo.Length;
|
||||||
|
|
||||||
|
// Write metadata
|
||||||
|
FileSystem::FileWriter meta(Utils::VA("%s.json", Theatre::DemoContainer.CurrentInfo.Name.data()));
|
||||||
|
meta.Write(json11::Json(Theatre::DemoContainer.CurrentInfo).dump());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theatre::LoadDemos()
|
||||||
|
{
|
||||||
|
Theatre::DemoContainer.CurrentSelection = 0;
|
||||||
|
Theatre::DemoContainer.Demos.clear();
|
||||||
|
|
||||||
|
auto demos = FileSystem::GetFileList("demos/", "dm_13");
|
||||||
|
|
||||||
|
for (auto demo : demos)
|
||||||
|
{
|
||||||
|
FileSystem::File meta(Utils::VA("demos/%s.json", demo.data()));
|
||||||
|
|
||||||
|
if (meta.Exists())
|
||||||
|
{
|
||||||
|
std::string error;
|
||||||
|
json11::Json metaObject = json11::Json::parse(meta.GetBuffer(), error);
|
||||||
|
|
||||||
|
if (metaObject.is_object())
|
||||||
|
{
|
||||||
|
Theatre::Container::DemoInfo info;
|
||||||
|
|
||||||
|
info.Name = demo.substr(0, demo.find_last_of("."));
|
||||||
|
info.Author = metaObject["author"].string_value();
|
||||||
|
info.Gametype = metaObject["gametype"].string_value();
|
||||||
|
info.Mapname = metaObject["mapname"].string_value();
|
||||||
|
info.Length = (int)metaObject["length"].number_value();
|
||||||
|
info.TimeStamp = _atoi64(metaObject["timestamp"].string_value().data());
|
||||||
|
|
||||||
|
Theatre::DemoContainer.Demos.push_back(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse, latest demo first!
|
||||||
|
std::reverse(Theatre::DemoContainer.Demos.begin(), Theatre::DemoContainer.Demos.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theatre::DeleteDemo()
|
||||||
|
{
|
||||||
|
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
||||||
|
{
|
||||||
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection];
|
||||||
|
|
||||||
|
Logger::Print("Deleting demo %s...\n", info.Name.data());
|
||||||
|
|
||||||
|
FileSystem::DeleteFile("demos", info.Name + ".dm_13");
|
||||||
|
FileSystem::DeleteFile("demos", info.Name + ".dm_13.json");
|
||||||
|
|
||||||
|
// Reload demos
|
||||||
|
Theatre::LoadDemos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theatre::PlayDemo()
|
||||||
|
{
|
||||||
|
if (Theatre::DemoContainer.CurrentSelection < Theatre::DemoContainer.Demos.size())
|
||||||
|
{
|
||||||
|
Command::Execute(Utils::VA("demo %s", Theatre::DemoContainer.Demos[Theatre::DemoContainer.CurrentSelection].Name.data()), true);
|
||||||
|
Command::Execute("demoback", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int Theatre::GetDemoCount()
|
||||||
|
{
|
||||||
|
return Theatre::DemoContainer.Demos.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Omit column here
|
||||||
|
const char* Theatre::GetDemoText(unsigned int item, int column)
|
||||||
|
{
|
||||||
|
if (item < Theatre::DemoContainer.Demos.size())
|
||||||
|
{
|
||||||
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[item];
|
||||||
|
|
||||||
|
return Utils::VA("%s on %s", Game::UI_LocalizeGameType(info.Gametype.data()), Game::UI_LocalizeMapName(info.Mapname.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Theatre::SelectDemo(unsigned int index)
|
||||||
|
{
|
||||||
|
if (index < Theatre::DemoContainer.Demos.size())
|
||||||
|
{
|
||||||
|
Theatre::DemoContainer.CurrentSelection = index;
|
||||||
|
Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[index];
|
||||||
|
|
||||||
|
Dvar::Var("ui_demo_mapname").Set(info.Mapname);
|
||||||
|
Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data()));
|
||||||
|
Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data()));
|
||||||
|
Dvar::Var("ui_demo_length").Set(info.Length); // TODO: Parse as readable string
|
||||||
|
Dvar::Var("ui_demo_author").Set(info.Author);
|
||||||
|
Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Theatre::Theatre()
|
Theatre::Theatre()
|
||||||
{
|
{
|
||||||
Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x5A8370, Theatre::GamestateWriteStub, HOOK_CALL).Install()->Quick();
|
||||||
@ -158,10 +279,23 @@ namespace Components
|
|||||||
Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).Install()->Quick();
|
Utils::Hook(0x50320E, Theatre::AdjustTimeDeltaStub, HOOK_CALL).Install()->Quick();
|
||||||
Utils::Hook(0x5A8E03, Theatre::ServerTimedOutStub, HOOK_JUMP).Install()->Quick();
|
Utils::Hook(0x5A8E03, Theatre::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();
|
||||||
|
|
||||||
|
// UIScripts
|
||||||
|
UIScript::Add("loadDemos", Theatre::LoadDemos);
|
||||||
|
UIScript::Add("launchDemo", Theatre::PlayDemo);
|
||||||
|
UIScript::Add("deleteDemo", Theatre::DeleteDemo);
|
||||||
|
|
||||||
|
// Feeder
|
||||||
|
UIFeeder::Add(10.0f, Theatre::GetDemoCount, Theatre::GetDemoText, Theatre::SelectDemo);
|
||||||
|
|
||||||
// set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps
|
// set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps
|
||||||
if(!Dedicated::IsDedicated()) Utils::Hook::Set<char*>(0x47440B, "mp/defaultStringTable.csv");
|
if(!Dedicated::IsDedicated()) Utils::Hook::Set<char*>(0x47440B, "mp/defaultStringTable.csv");
|
||||||
|
|
||||||
*(BYTE*)0x5AC854 = 4;
|
// Change font size
|
||||||
*(BYTE*)0x5AC85A = 4;
|
Utils::Hook::Set<BYTE>(0x5AC854, 2);
|
||||||
|
Utils::Hook::Set<BYTE>(0x5AC85A, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,37 @@ namespace Components
|
|||||||
const char* GetName() { return "Theatre"; };
|
const char* GetName() { return "Theatre"; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Container
|
||||||
|
{
|
||||||
|
struct DemoInfo
|
||||||
|
{
|
||||||
|
std::string Name;
|
||||||
|
std::string Mapname;
|
||||||
|
std::string Gametype;
|
||||||
|
std::string Author;
|
||||||
|
int Length;
|
||||||
|
std::time_t TimeStamp;
|
||||||
|
|
||||||
|
json11::Json to_json() const
|
||||||
|
{
|
||||||
|
return json11::Json::object
|
||||||
|
{
|
||||||
|
{ "mapname", Mapname },
|
||||||
|
{ "gametype", Gametype },
|
||||||
|
{ "author", Author },
|
||||||
|
{ "length", Length },
|
||||||
|
{ "timestamp", Utils::VA("%lld", TimeStamp) } //Ugly, but prevents information loss
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DemoInfo CurrentInfo;
|
||||||
|
unsigned int CurrentSelection;
|
||||||
|
std::vector<DemoInfo> Demos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Container DemoContainer;
|
||||||
|
|
||||||
static char BaselineSnapshot[131072];
|
static char BaselineSnapshot[131072];
|
||||||
static PBYTE BaselineSnapshotMsg;
|
static PBYTE BaselineSnapshotMsg;
|
||||||
static int BaselineSnapshotMsgLen;
|
static int BaselineSnapshotMsgLen;
|
||||||
@ -14,6 +45,14 @@ namespace Components
|
|||||||
|
|
||||||
static void WriteBaseline();
|
static void WriteBaseline();
|
||||||
|
|
||||||
|
static void LoadDemos();
|
||||||
|
static void DeleteDemo();
|
||||||
|
static void PlayDemo();
|
||||||
|
|
||||||
|
static unsigned int GetDemoCount();
|
||||||
|
static const char* GetDemoText(unsigned int item, int column);
|
||||||
|
static void SelectDemo(unsigned int index);
|
||||||
|
|
||||||
static void GamestateWriteStub(Game::msg_t* msg, char byte);
|
static void GamestateWriteStub(Game::msg_t* msg, char byte);
|
||||||
static void RecordGamestateStub();
|
static void RecordGamestateStub();
|
||||||
static void BaselineStoreStub();
|
static void BaselineStoreStub();
|
||||||
@ -21,5 +60,8 @@ namespace Components
|
|||||||
static void AdjustTimeDeltaStub();
|
static void AdjustTimeDeltaStub();
|
||||||
static void ServerTimedOutStub();
|
static void ServerTimedOutStub();
|
||||||
static void UISetActiveMenuStub();
|
static void UISetActiveMenuStub();
|
||||||
|
|
||||||
|
static void RecordStub(int channel, char* message, char* file);
|
||||||
|
static void StopRecordStub(int channel, char* message);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace Components
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int UIFeeder::GetItemCount()
|
unsigned int UIFeeder::GetItemCount()
|
||||||
{
|
{
|
||||||
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
|
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
|
||||||
{
|
{
|
||||||
@ -65,7 +65,7 @@ namespace Components
|
|||||||
retn
|
retn
|
||||||
|
|
||||||
continue:
|
continue:
|
||||||
fld ds : 739FD0h
|
fld ds:739FD0h
|
||||||
|
|
||||||
mov eax, 4C25D6h
|
mov eax, 4C25D6h
|
||||||
jmp eax
|
jmp eax
|
||||||
|
@ -3,9 +3,9 @@ namespace Components
|
|||||||
class UIFeeder : public Component
|
class UIFeeder : public Component
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef int(__cdecl * GetItemCount_t)();
|
typedef unsigned int(__cdecl * GetItemCount_t)();
|
||||||
typedef const char* (__cdecl * GetItemText_t)(int index, int column);
|
typedef const char* (__cdecl * GetItemText_t)(unsigned int index, int column);
|
||||||
typedef void(__cdecl * Select_t)(int index);
|
typedef void(__cdecl * Select_t)(unsigned int index);
|
||||||
|
|
||||||
struct Callbacks
|
struct Callbacks
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ namespace Components
|
|||||||
static Container Current;
|
static Container Current;
|
||||||
|
|
||||||
static void GetItemCountStub();
|
static void GetItemCountStub();
|
||||||
static int GetItemCount();
|
static unsigned int GetItemCount();
|
||||||
|
|
||||||
static void GetItemTextStub();
|
static void GetItemTextStub();
|
||||||
static const char* GetItemText();
|
static const char* GetItemText();
|
||||||
|
@ -102,7 +102,7 @@ namespace Game
|
|||||||
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
|
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
|
||||||
extern FS_FreeFileList_t FS_FreeFileList;
|
extern FS_FreeFileList_t FS_FreeFileList;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_FOpenFileAppend_t)(char* file);
|
typedef int(__cdecl * FS_FOpenFileAppend_t)(const char* file);
|
||||||
extern FS_FOpenFileAppend_t FS_FOpenFileAppend;
|
extern FS_FOpenFileAppend_t FS_FOpenFileAppend;
|
||||||
extern FS_FOpenFileAppend_t FS_FOpenFileWrite;
|
extern FS_FOpenFileAppend_t FS_FOpenFileWrite;
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ namespace Game
|
|||||||
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
|
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
|
||||||
extern FS_WriteFile_t FS_WriteFile;
|
extern FS_WriteFile_t FS_WriteFile;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Write_t)(void* buffer, size_t size, int file);
|
typedef int(__cdecl * FS_Write_t)(const void* buffer, size_t size, int file);
|
||||||
extern FS_Write_t FS_Write;
|
extern FS_Write_t FS_Write;
|
||||||
|
|
||||||
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
|
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user