Merge branch 'master'

This commit is contained in:
sr0 2016-01-10 13:25:17 +01:00
commit 519c298b0b
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>();
// Ignores " for now, too lazy to implement
// TODO: Implement!
auto tokens = Utils::Explode(rotation, ' ');
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());
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
{
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)
{
return !File(execFilename).Exists();

View File

@ -21,9 +21,28 @@ namespace Components
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();
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:
static int ExecIsFSStub(const char* execFilename);
};

View File

@ -4,14 +4,14 @@ namespace Components
{
ServerInfo::Container ServerInfo::PlayerContainer;
int ServerInfo::GetPlayerCount()
unsigned int ServerInfo::GetPlayerCount()
{
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)
{
@ -32,7 +32,7 @@ namespace Components
return "";
}
void ServerInfo::SelectPlayer(int index)
void ServerInfo::SelectPlayer(unsigned int index)
{
ServerInfo::PlayerContainer.CurrentPlayer = index;
}

View File

@ -17,7 +17,7 @@ namespace Components
std::string Name;
};
int CurrentPlayer;
unsigned int CurrentPlayer;
std::vector<Player> PlayerList;
Network::Address Target;
};
@ -26,8 +26,8 @@ namespace Components
static void ServerStatus();
static int GetPlayerCount();
static const char* GetPlayerText(int index, int column);
static void SelectPlayer(int index);
static unsigned int GetPlayerCount();
static const char* GetPlayerText(unsigned int index, int column);
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::FavouriteList;
std::vector<int> ServerList::VisibleList;
std::vector<unsigned int> ServerList::VisibleList;
std::vector<ServerList::ServerInfo>* ServerList::GetList()
{
@ -49,12 +49,12 @@ namespace Components
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);
@ -121,9 +121,9 @@ namespace Components
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();
@ -412,8 +412,8 @@ namespace Components
{
qsort(ServerList::VisibleList.data(), ServerList::VisibleList.size(), sizeof(int), [] (const void* first, const void* second)
{
int server1 = *(int*)first;
int server2 = *(int*)second;
unsigned int server1 = *(unsigned int*)first;
unsigned int server2 = *(unsigned int*)second;
ServerInfo* info1 = nullptr;
ServerInfo* info2 = nullptr;
@ -421,8 +421,8 @@ namespace Components
auto list = ServerList::GetList();
if (!list) return 0;
if (list->size() > (unsigned int)server1) info1 = &(*list)[server1];
if (list->size() > (unsigned int)server2) info2 = &(*list)[server2];
if (list->size() > server1) info1 = &(*list)[server1];
if (list->size() > server2) info2 = &(*list)[server2];
if (!info1) 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();
if (!list) return nullptr;
if (list->size() > (unsigned int)ServerList::VisibleList[index])
if (list->size() > ServerList::VisibleList[index])
{
return &(*list)[ServerList::VisibleList[index]];
}

View File

@ -93,10 +93,10 @@ namespace Components
std::mutex Mutex;
};
static int GetServerCount();
static const char* GetServerText(int index, int column);
static unsigned int GetServerCount();
static const char* GetServerText(unsigned int index, 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 UpdateGameType();
@ -108,7 +108,7 @@ namespace Components
static void LoadFavourties();
static void StoreFavourite(std::string server);
static ServerInfo* GetServer(int index);
static ServerInfo* GetServer(unsigned int index);
static std::vector<ServerInfo>* GetList();
static int SortKey;
@ -121,6 +121,6 @@ namespace Components
static std::vector<ServerInfo> OfflineList;
static std::vector<ServerInfo> FavouriteList;
static std::vector<int> VisibleList;
static std::vector<unsigned int> VisibleList;
};
}

View File

@ -2,6 +2,8 @@
namespace Components
{
Theatre::Container Theatre::DemoContainer;
char Theatre::BaselineSnapshot[131072] = { 0 };
PBYTE Theatre::BaselineSnapshotMsg = 0;
int Theatre::BaselineSnapshotMsgLen;
@ -129,17 +131,17 @@ namespace Components
void __declspec(naked) Theatre::UISetActiveMenuStub()
{
if (*Game::demoPlaying == 1)
{
__asm
{
mov eax, 4CB49Ch
jmp eax
}
}
__asm
{
mov eax, Game::demoPlaying
mov eax, [eax]
test al, al
jz continue
mov eax, 4CB49Ch
jmp eax
continue:
mov ecx, [esp + 10h]
push 10h
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()
{
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(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
if(!Dedicated::IsDedicated()) Utils::Hook::Set<char*>(0x47440B, "mp/defaultStringTable.csv");
*(BYTE*)0x5AC854 = 4;
*(BYTE*)0x5AC85A = 4;
// Change font size
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"; };
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 PBYTE BaselineSnapshotMsg;
static int BaselineSnapshotMsgLen;
@ -14,6 +45,14 @@ namespace Components
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 RecordGamestateStub();
static void BaselineStoreStub();
@ -21,5 +60,8 @@ namespace Components
static void AdjustTimeDeltaStub();
static void ServerTimedOutStub();
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;
}
int UIFeeder::GetItemCount()
unsigned int UIFeeder::GetItemCount()
{
if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end())
{
@ -65,7 +65,7 @@ namespace Components
retn
continue:
fld ds : 739FD0h
fld ds:739FD0h
mov eax, 4C25D6h
jmp eax

View File

@ -3,9 +3,9 @@ namespace Components
class UIFeeder : public Component
{
public:
typedef int(__cdecl * GetItemCount_t)();
typedef const char* (__cdecl * GetItemText_t)(int index, int column);
typedef void(__cdecl * Select_t)(int index);
typedef unsigned int(__cdecl * GetItemCount_t)();
typedef const char* (__cdecl * GetItemText_t)(unsigned int index, int column);
typedef void(__cdecl * Select_t)(unsigned int index);
struct Callbacks
{
@ -31,7 +31,7 @@ namespace Components
static Container Current;
static void GetItemCountStub();
static int GetItemCount();
static unsigned int GetItemCount();
static void GetItemTextStub();
static const char* GetItemText();

View File

@ -102,7 +102,7 @@ namespace Game
typedef void(__cdecl * FS_FreeFileList_t)(char** list);
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_FOpenFileWrite;
@ -118,7 +118,7 @@ namespace Game
typedef bool(__cdecl * FS_WriteFile_t)(char* filename, char* folder, void* buffer, int size);
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;
typedef int(__cdecl * FS_Read_t)(void* buffer, size_t size, int file);