Threater stuff.

This commit is contained in:
momo5502 2016-01-10 12:25:31 +01:00
parent 0bcbd75787
commit d28cbd956e
12 changed files with 291 additions and 52 deletions

View File

@ -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());

View File

@ -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();

View File

@ -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);
}; };

View File

@ -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;
} }

View File

@ -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);
}; };
} }

View File

@ -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]];
} }

View File

@ -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;
}; };
} }

View File

@ -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);
} }
} }

View File

@ -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);
}; };
} }

View File

@ -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

View File

@ -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();

View File

@ -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);