From 03fac2e63782c65896983b5070af74b1001d9f57 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Mon, 28 Dec 2015 14:08:46 +0100 Subject: [PATCH] Add UIScript support. --- iw4/Components/Feeder.cpp | 285 -------------------- iw4/Components/Loader.cpp | 3 +- iw4/Components/Loader.hpp | 3 +- iw4/Components/Menus.cpp | 109 +++++--- iw4/Components/Menus.hpp | 6 +- iw4/Components/Party.cpp | 8 +- iw4/Components/ServerList.cpp | 36 ++- iw4/Components/ServerList.hpp | 2 +- iw4/Components/UIFeeder.cpp | 285 ++++++++++++++++++++ iw4/Components/{Feeder.hpp => UIFeeder.hpp} | 10 +- iw4/Components/UIScript.cpp | 110 ++++++++ iw4/Components/UIScript.hpp | 39 +++ iw4/Game/Functions.cpp | 1 + iw4/Game/Functions.hpp | 3 + iw4/Main.cpp | 4 +- iw4/Utils/Hooking.cpp | 5 + iw4/Utils/Hooking.hpp | 1 + iw4/iw4.vcxproj | 6 +- iw4/iw4.vcxproj.filters | 14 +- 19 files changed, 570 insertions(+), 360 deletions(-) delete mode 100644 iw4/Components/Feeder.cpp create mode 100644 iw4/Components/UIFeeder.cpp rename iw4/Components/{Feeder.hpp => UIFeeder.hpp} (87%) create mode 100644 iw4/Components/UIScript.cpp create mode 100644 iw4/Components/UIScript.hpp diff --git a/iw4/Components/Feeder.cpp b/iw4/Components/Feeder.cpp deleted file mode 100644 index 67a082b8..00000000 --- a/iw4/Components/Feeder.cpp +++ /dev/null @@ -1,285 +0,0 @@ -#include "..\STDInclude.hpp" - -namespace Components -{ - Feeder::Container Feeder::Current; - std::map Feeder::Feeders; - - void Feeder::Add(float feeder, Feeder::GetItemCount_t itemCountCb, Feeder::GetItemText_t itemTextCb, Feeder::Select_t selectCb) - { - Feeder::Feeders[feeder] = { itemCountCb, itemTextCb, selectCb }; - } - - const char* Feeder::GetItemText() - { - if (Feeder::Feeders.find(Feeder::Current.Num) != Feeder::Feeders.end()) - { - return Feeder::Feeders[Feeder::Current.Num].GetItemText(Feeder::Current.Index, Feeder::Current.Column); - } - - return nullptr; - } - - int Feeder::GetItemCount() - { - if (Feeder::Feeders.find(Feeder::Current.Num) != Feeder::Feeders.end()) - { - return Feeder::Feeders[Feeder::Current.Num].GetItemCount(); - } - - return 0; - } - - bool Feeder::SetItemSelection() - { - if (Feeder::Feeders.find(Feeder::Current.Num) != Feeder::Feeders.end()) - { - Feeder::Feeders[Feeder::Current.Num].Select(Feeder::Current.Index); - return true; - } - - return false; - } - - bool Feeder::CheckFeeder() - { - if (Feeder::Current.Num == 15.0f) return false; - return (Feeder::Feeders.find(Feeder::Current.Num) != Feeder::Feeders.end()); - } - - void __declspec(naked) Feeder::SetItemSelectionStub() - { - __asm - { - mov eax, [esp + 08h] - mov Feeder::Current.Num, eax - - mov eax, [esp + 0Ch] - mov Feeder::Current.Index, eax - - call Feeder::SetItemSelection - - test eax, eax - jz continue - - retn - - continue: - fld ds : 739FD0h - - mov eax, 4C25D6h - jmp eax - } - } - - void __declspec(naked) Feeder::GetItemTextStub() - { - __asm - { - mov eax, [esp + 0Ch] - mov Feeder::Current.Num, eax - - mov eax, [esp + 10h] - mov Feeder::Current.Index, eax - - mov eax, [esp + 14h] - mov Feeder::Current.Column, eax - - call Feeder::GetItemText - - test eax, eax - jz continue - - push ebx - mov ebx, [esp + 4 + 28h] - mov dword ptr[ebx], 0 - pop ebx - retn - - continue: - push ecx - fld ds:739FD0h - - mov eax, 4CE9E7h - jmp eax - } - } - - void __declspec(naked) Feeder::GetItemCountStub() - { - __asm - { - mov eax, [esp + 8h] - mov Feeder::Current.Num, eax - - call Feeder::GetItemCount - - test eax, eax - jz continue - - retn - - continue: - push ecx - fld ds:739FD0h - - mov eax, 41A0D7h - jmp eax; - } - } - - void __declspec(naked) Feeder::HandleKeyStub() - { - static int NextClickTime = 0; - - __asm - { - mov ebx, ebp - mov eax, [ebp + 12Ch] - mov Feeder::Current.Num, eax - - push ebx - call Feeder::CheckFeeder - pop ebx - - test eax, eax - jz continueOriginal - - // Get current milliseconds - call Game::Com_Milliseconds - - // Check if allowed to click - cmp eax, NextClickTime - jl continueOriginal - - // Set next allowed click time to current time + 300ms - add eax, 300 - mov NextClickTime, eax - - // Get item cursor position ptr - mov ecx, ebx - add ecx, Game::itemDef_t::cursorPos - - // Get item listbox ptr - mov edx, ebx - add edx, Game::itemDef_t::typeData - - // Get listbox cursor pos - mov edx, [edx] - add edx, Game::listBoxDef_s::startPos - mov edx, [edx] - - // Resolve item cursor pos pointer - mov ebx, [ecx] - - // Check if item cursor pos equals listbox cursor pos - cmp ebx, edx - je returnSafe - - // Update indices if not - mov [ecx], edx - mov Feeder::Current.Index, edx - - call Feeder::SetItemSelection - - returnSafe: - retn - - continueOriginal: - mov eax, 635570h - jmp eax - } - } - - void __declspec(naked) Feeder::MouseEnterStub() - { - __asm - { - mov eax, [edi + 12Ch] - mov Feeder::Current.Num, eax - - call Feeder::CheckFeeder - - test eax, eax - jnz continue - - mov[edi + 130h], esi - - continue: - mov eax, 639D75h - jmp eax - } - } - - void __declspec(naked) Feeder::MouseSelectStub() - { - __asm - { - mov eax, [esp + 08h] - mov Feeder::Current.Num, eax - - call Feeder::CheckFeeder - - test eax, eax - jnz continue - - mov eax, 4C25D0h - jmp eax - - continue: - retn - } - } - - void __declspec(naked) Feeder::PlaySoundStub() - { - __asm - { - mov eax, [edi + 12Ch] - mov Feeder::Current.Num, eax - - call Feeder::CheckFeeder - - test eax, eax - jnz continue - - mov eax, 685E10h - jmp eax - - continue: - retn - } - } - - Feeder::Feeder() - { - // Get feeder item count - Utils::Hook(0x41A0D0, Feeder::GetItemCountStub, HOOK_JUMP).Install()->Quick(); - - // Get feeder item text - Utils::Hook(0x4CE9E0, Feeder::GetItemTextStub, HOOK_JUMP).Install()->Quick(); - - // Select feeder item - Utils::Hook(0x4C25D0, Feeder::SetItemSelectionStub, HOOK_JUMP).Install()->Quick(); - - // Mouse enter check - Utils::Hook(0x639D6E, Feeder::MouseEnterStub, HOOK_JUMP).Install()->Quick(); - - // Handle key event - Utils::Hook(0x63C5BC, Feeder::HandleKeyStub, HOOK_CALL).Install()->Quick(); - - // Mouse select check - Utils::Hook(0x639D31, Feeder::MouseSelectStub, HOOK_CALL).Install()->Quick(); - - // Play mouse over sound check - Utils::Hook(0x639D66, Feeder::PlaySoundStub, HOOK_CALL).Install()->Quick(); - - // some thing overwriting feeder 2's data - Utils::Hook::Set(0x4A06A9, 0xEB); - } - - Feeder::~Feeder() - { - Feeder::Feeders.clear(); - } -} diff --git a/iw4/Components/Loader.cpp b/iw4/Components/Loader.cpp index 9e09571f..e5361593 100644 --- a/iw4/Components/Loader.cpp +++ b/iw4/Components/Loader.cpp @@ -13,7 +13,6 @@ namespace Components Loader::Register(new Menus()); Loader::Register(new Party()); Loader::Register(new Colors()); - Loader::Register(new Feeder()); Loader::Register(new Logger()); Loader::Register(new Window()); Loader::Register(new Command()); @@ -21,6 +20,8 @@ namespace Components Loader::Register(new Network()); Loader::Register(new RawFiles()); Loader::Register(new Renderer()); + Loader::Register(new UIFeeder()); + Loader::Register(new UIScript()); Loader::Register(new FastFiles()); Loader::Register(new Materials()); Loader::Register(new Singleton()); diff --git a/iw4/Components/Loader.hpp b/iw4/Components/Loader.hpp index b503acb4..e88131ee 100644 --- a/iw4/Components/Loader.hpp +++ b/iw4/Components/Loader.hpp @@ -24,7 +24,6 @@ namespace Components #include "Maps.hpp" #include "Menus.hpp" #include "Colors.hpp" -#include "Feeder.hpp" #include "Logger.hpp" #include "Window.hpp" #include "Command.hpp" @@ -33,6 +32,8 @@ namespace Components #include "Party.hpp" // Destroys the order, but requires network classes :D #include "RawFiles.hpp" #include "Renderer.hpp" +#include "UIFeeder.hpp" +#include "UIScript.hpp" #include "Dedicated.hpp" #include "FastFiles.hpp" #include "Materials.hpp" diff --git a/iw4/Components/Menus.cpp b/iw4/Components/Menus.cpp index 69a91060..bb3526a2 100644 --- a/iw4/Components/Menus.cpp +++ b/iw4/Components/Menus.cpp @@ -24,11 +24,11 @@ namespace Components return i; } - Game::script_t* Menus::LoadMenuScript(const char* name, std::string buffer) + Game::script_t* Menus::LoadMenuScript(std::string name, std::string buffer) { Game::script_t* script = Game::Script_Alloc(sizeof(Game::script_t) + 1 + buffer.length()); - strcpy_s(script->filename, sizeof(script->filename), name); + strcpy_s(script->filename, sizeof(script->filename), name.data()); script->buffer = (char*)(script + 1); *((char*)(script + 1) + buffer.length()) = '\0'; @@ -51,7 +51,7 @@ namespace Components return script; } - int Menus::LoadMenuSource(const char* name, std::string buffer) + int Menus::LoadMenuSource(std::string name, std::string buffer) { int handle = Menus::ReserveSourceHandle(); if (!Menus::IsValidSourceHandle(handle)) return 0; // No free source slot! @@ -156,55 +156,56 @@ namespace Components return menu; } - std::vector Menus::LoadMenu(Game::menuDef_t* menudef) + std::vector Menus::LoadMenu(std::string menu) { std::vector menus; - FileSystem::File menuFile(Utils::VA("ui_mp\\%s.menu", menudef->window.name)); + FileSystem::File menuFile(menu); if (menuFile.Exists()) { Game::pc_token_t token; - int handle = Menus::LoadMenuSource(menudef->window.name, menuFile.GetBuffer()); - if (!Menus::IsValidSourceHandle(handle)) + int handle = Menus::LoadMenuSource(menu, menuFile.GetBuffer()); + + if (Menus::IsValidSourceHandle(handle)) { - menus.push_back(menudef); - return menus; - } - - while (true) - { - ZeroMemory(&token, sizeof(token)); - - if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] == '}') + while (true) { - break; - } + ZeroMemory(&token, sizeof(token)); - if (!_stricmp(token.string, "loadmenu")) - { - Game::PC_ReadTokenHandle(handle, &token); - - // Ugly, but does the job ;) - Game::menuDef_t _temp; - _temp.window.name = token.string; - - std::vector newMenus = Menus::LoadMenu(&_temp); - - for (auto newMenu : newMenus) + if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] == '}') { - menus.push_back(newMenu); + break; + } + + if (!_stricmp(token.string, "loadmenu")) + { + Game::PC_ReadTokenHandle(handle, &token); + + std::vector newMenus = Menus::LoadMenu(Utils::VA("ui_mp\\%s.menu", token.string)); + + for (auto newMenu : newMenus) + { + menus.push_back(newMenu); + } + } + + if (!_stricmp(token.string, "menudef")) + { + menus.push_back(Menus::ParseMenu(handle)); } } - if (!_stricmp(token.string, "menudef")) - { - menus.push_back(Menus::ParseMenu(handle)); - } + Menus::FreeMenuSource(handle); } - - Menus::FreeMenuSource(handle); } + return menus; + } + + std::vector Menus::LoadMenu(Game::menuDef_t* menudef) + { + std::vector menus = Menus::LoadMenu(Utils::VA("ui_mp\\%s.menu", menudef->window.name)); + if (!menus.size()) { menus.push_back(menudef); @@ -213,6 +214,25 @@ namespace Components return menus; } + Game::MenuList* Menus::LoadScriptMenu(const char* menu) + { + std::vector menus = Menus::LoadMenu(menu); + if (!menus.size()) return nullptr; + + // Allocate new menu list + Game::MenuList* newList = (Game::MenuList*)calloc(1, sizeof(Game::MenuList)); + newList->name = _strdup(menu); + newList->menus = (Game::menuDef_t **)calloc(menus.size(), sizeof(Game::menuDef_t *)); + newList->menuCount = menus.size(); + + // Copy new menus + memcpy(newList->menus, menus.data(), menus.size() * sizeof(Game::menuDef_t *)); + + Menus::MenuListList.push_back(newList); + + return newList; + } + Game::MenuList* Menus::LoadMenuList(Game::MenuList* menuList) { std::vector menus; @@ -401,8 +421,21 @@ namespace Components if (menuList) { - // Don't parse scriptmenus for now! - if (strcmp(menuList->menus[0]->window.name, "default_menu") && !Utils::EndsWith(filename, ".menu")) + // Parse scriptmenus! + if (!strcmp(menuList->menus[0]->window.name, "default_menu") || Utils::EndsWith(filename, ".menu")) + { + if (FileSystem::File(filename).Exists()) + { + header.menuList = Menus::LoadScriptMenu(filename); + + // Reset, if we didn't find scriptmenus + if (!header.menuList) + { + header.menuList = menuList; + } + } + } + else { header.menuList = Menus::LoadMenuList(menuList); } diff --git a/iw4/Components/Menus.hpp b/iw4/Components/Menus.hpp index 28edabff..c9288cb9 100644 --- a/iw4/Components/Menus.hpp +++ b/iw4/Components/Menus.hpp @@ -17,10 +17,12 @@ namespace Components static Game::XAssetHeader MenuFileLoad(Game::XAssetType type, const char* filename); static Game::MenuList* LoadMenuList(Game::MenuList* menuList); + static Game::MenuList* LoadScriptMenu(const char* menu); static std::vector LoadMenu(Game::menuDef_t* menudef); + static std::vector LoadMenu(std::string file); - static Game::script_t* LoadMenuScript(const char* name, std::string buffer); - static int LoadMenuSource(const char* name, std::string buffer); + static Game::script_t* LoadMenuScript(std::string name, std::string buffer); + static int LoadMenuSource(std::string name, std::string buffer); static int ReserveSourceHandle(); static bool IsValidSourceHandle(int handle); diff --git a/iw4/Components/Party.cpp b/iw4/Components/Party.cpp index 86324d65..1e61e7da 100644 --- a/iw4/Components/Party.cpp +++ b/iw4/Components/Party.cpp @@ -182,7 +182,6 @@ namespace Components Network::Handle("infoResponse", [] (Network::Address address, std::string data) { - OutputDebugStringA(data.data()); Utils::InfoString info(data); // Handle connection @@ -199,10 +198,6 @@ namespace Components { Party::ConnectError("Invalid join response: Challenge mismatch."); } - else if (matchType < 0 || 2 < matchType) - { - Party::ConnectError("Invalid join response: Unknown matchtype"); - } else if (!matchType) { Party::ConnectError("Server is not hosting a match."); @@ -242,8 +237,7 @@ namespace Components } else { - // WAT? - OutputDebugStringA("WAT?"); + Party::ConnectError("Invalid join response: Unknown matchtype"); } } } diff --git a/iw4/Components/ServerList.cpp b/iw4/Components/ServerList.cpp index 368f6757..928391f5 100644 --- a/iw4/Components/ServerList.cpp +++ b/iw4/Components/ServerList.cpp @@ -2,7 +2,7 @@ namespace Components { - int ServerList::CurrentServer = 0; + unsigned int ServerList::CurrentServer = 0; ServerList::Container ServerList::RefreshContainer; std::vector ServerList::OnlineList; @@ -13,7 +13,7 @@ namespace Components const char* ServerList::GetServerText(int index, int column) { - if (index >= (int)ServerList::OnlineList.size()) return ""; + if ((unsigned int)index >= ServerList::OnlineList.size()) return ""; ServerList::ServerInfo* Server = &ServerList::OnlineList[index]; @@ -60,7 +60,7 @@ namespace Components void ServerList::SelectServer(int index) { - ServerList::CurrentServer = index; + ServerList::CurrentServer = (unsigned int)index; } void ServerList::Refresh() @@ -113,6 +113,7 @@ namespace Components server.MaxClients = atoi(info.Get("sv_maxclients").data()); server.Password = 0; // No info yet server.Ping = (Game::Com_Milliseconds() - i->SendTime); + server.Addr = address; ServerList::OnlineList.push_back(server); @@ -129,9 +130,6 @@ namespace Components { ServerList::OnlineList.clear(); - // Add server list feeder - Feeder::Add(2.0f, ServerList::GetServerCount, ServerList::GetServerText, ServerList::SelectServer); - Network::Handle("getServersResponse", [] (Network::Address address, std::string data) { if (!ServerList::RefreshContainer.AwaitingList) return; // Only parse if we are awaiting a list @@ -179,13 +177,27 @@ namespace Components ServerList::RefreshContainer.Mutex.unlock(); }); - Command::Add("refreshList", [] (Command::Params params) - { - ServerList::Refresh(); - }); + // Set default masterServerName + port and save it + Utils::Hook::Set(0x60AD92, "localhost"); + Utils::Hook::Set(0x60AD90, Game::dvar_flag::DVAR_FLAG_SAVED); // masterServerName + Utils::Hook::Set(0x60ADC6, Game::dvar_flag::DVAR_FLAG_SAVED); // masterPort - // Temporary overwriting - strcpy((char*)0x6D9CBC, "localhost"); + // Add server list feeder + UIFeeder::Add(2.0f, ServerList::GetServerCount, ServerList::GetServerText, ServerList::SelectServer); + + // Add required UIScripts + UIScript::Add("RefreshServers", ServerList::Refresh); + UIScript::Add("JoinServer", [] () + { + if (ServerList::OnlineList.size() > ServerList::CurrentServer) + { + Party::Connect(ServerList::OnlineList[ServerList::CurrentServer].Addr); + } + }); + UIScript::Add("ServerSort", [] (UIScript::Token token) + { + Logger::Print("Server list sorting by token: %d\n", token.Get()); + }); } ServerList::~ServerList() diff --git a/iw4/Components/ServerList.hpp b/iw4/Components/ServerList.hpp index 40e5398d..fdc249ce 100644 --- a/iw4/Components/ServerList.hpp +++ b/iw4/Components/ServerList.hpp @@ -57,7 +57,7 @@ namespace Components static const char* GetServerText(int index, int column); static void SelectServer(int index); - static int CurrentServer; + static unsigned int CurrentServer; static Container RefreshContainer; static std::vector OnlineList; }; diff --git a/iw4/Components/UIFeeder.cpp b/iw4/Components/UIFeeder.cpp new file mode 100644 index 00000000..824d1960 --- /dev/null +++ b/iw4/Components/UIFeeder.cpp @@ -0,0 +1,285 @@ +#include "..\STDInclude.hpp" + +namespace Components +{ + UIFeeder::Container UIFeeder::Current; + std::map UIFeeder::Feeders; + + void UIFeeder::Add(float feeder, UIFeeder::GetItemCount_t itemCountCb, UIFeeder::GetItemText_t itemTextCb, UIFeeder::Select_t selectCb) + { + UIFeeder::Feeders[feeder] = { itemCountCb, itemTextCb, selectCb }; + } + + const char* UIFeeder::GetItemText() + { + if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end()) + { + return UIFeeder::Feeders[UIFeeder::Current.Feeder].GetItemText(UIFeeder::Current.Index, UIFeeder::Current.Column); + } + + return nullptr; + } + + int UIFeeder::GetItemCount() + { + if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end()) + { + return UIFeeder::Feeders[UIFeeder::Current.Feeder].GetItemCount(); + } + + return 0; + } + + bool UIFeeder::SetItemSelection() + { + if (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end()) + { + UIFeeder::Feeders[UIFeeder::Current.Feeder].Select(UIFeeder::Current.Index); + return true; + } + + return false; + } + + bool UIFeeder::CheckFeeder() + { + if (UIFeeder::Current.Feeder == 15.0f) return false; + return (UIFeeder::Feeders.find(UIFeeder::Current.Feeder) != UIFeeder::Feeders.end()); + } + + void __declspec(naked) UIFeeder::SetItemSelectionStub() + { + __asm + { + mov eax, [esp + 08h] + mov UIFeeder::Current.Feeder, eax + + mov eax, [esp + 0Ch] + mov UIFeeder::Current.Index, eax + + call UIFeeder::SetItemSelection + + test eax, eax + jz continue + + retn + + continue: + fld ds : 739FD0h + + mov eax, 4C25D6h + jmp eax + } + } + + void __declspec(naked) UIFeeder::GetItemTextStub() + { + __asm + { + mov eax, [esp + 0Ch] + mov UIFeeder::Current.Feeder, eax + + mov eax, [esp + 10h] + mov UIFeeder::Current.Index, eax + + mov eax, [esp + 14h] + mov UIFeeder::Current.Column, eax + + call UIFeeder::GetItemText + + test eax, eax + jz continue + + push ebx + mov ebx, [esp + 4 + 28h] + mov dword ptr[ebx], 0 + pop ebx + retn + + continue: + push ecx + fld ds:739FD0h + + mov eax, 4CE9E7h + jmp eax + } + } + + void __declspec(naked) UIFeeder::GetItemCountStub() + { + __asm + { + mov eax, [esp + 8h] + mov UIFeeder::Current.Feeder, eax + + call UIFeeder::GetItemCount + + test eax, eax + jz continue + + retn + + continue: + push ecx + fld ds:739FD0h + + mov eax, 41A0D7h + jmp eax; + } + } + + void __declspec(naked) UIFeeder::HandleKeyStub() + { + static int NextClickTime = 0; + + __asm + { + mov ebx, ebp + mov eax, [ebp + 12Ch] + mov UIFeeder::Current.Feeder, eax + + push ebx + call UIFeeder::CheckFeeder + pop ebx + + test eax, eax + jz continueOriginal + + // Get current milliseconds + call Game::Com_Milliseconds + + // Check if allowed to click + cmp eax, NextClickTime + jl continueOriginal + + // Set next allowed click time to current time + 300ms + add eax, 300 + mov NextClickTime, eax + + // Get item cursor position ptr + mov ecx, ebx + add ecx, Game::itemDef_t::cursorPos + + // Get item listbox ptr + mov edx, ebx + add edx, Game::itemDef_t::typeData + + // Get listbox cursor pos + mov edx, [edx] + add edx, Game::listBoxDef_s::startPos + mov edx, [edx] + + // Resolve item cursor pos pointer + mov ebx, [ecx] + + // Check if item cursor pos equals listbox cursor pos + cmp ebx, edx + je returnSafe + + // Update indices if not + mov [ecx], edx + mov UIFeeder::Current.Index, edx + + call UIFeeder::SetItemSelection + + returnSafe: + retn + + continueOriginal: + mov eax, 635570h + jmp eax + } + } + + void __declspec(naked) UIFeeder::MouseEnterStub() + { + __asm + { + mov eax, [edi + 12Ch] + mov UIFeeder::Current.Feeder, eax + + call UIFeeder::CheckFeeder + + test eax, eax + jnz continue + + mov[edi + 130h], esi + + continue: + mov eax, 639D75h + jmp eax + } + } + + void __declspec(naked) UIFeeder::MouseSelectStub() + { + __asm + { + mov eax, [esp + 08h] + mov UIFeeder::Current.Feeder, eax + + call UIFeeder::CheckFeeder + + test eax, eax + jnz continue + + mov eax, 4C25D0h + jmp eax + + continue: + retn + } + } + + void __declspec(naked) UIFeeder::PlaySoundStub() + { + __asm + { + mov eax, [edi + 12Ch] + mov UIFeeder::Current.Feeder, eax + + call UIFeeder::CheckFeeder + + test eax, eax + jnz continue + + mov eax, 685E10h + jmp eax + + continue: + retn + } + } + + UIFeeder::UIFeeder() + { + // Get feeder item count + Utils::Hook(0x41A0D0, UIFeeder::GetItemCountStub, HOOK_JUMP).Install()->Quick(); + + // Get feeder item text + Utils::Hook(0x4CE9E0, UIFeeder::GetItemTextStub, HOOK_JUMP).Install()->Quick(); + + // Select feeder item + Utils::Hook(0x4C25D0, UIFeeder::SetItemSelectionStub, HOOK_JUMP).Install()->Quick(); + + // Mouse enter check + Utils::Hook(0x639D6E, UIFeeder::MouseEnterStub, HOOK_JUMP).Install()->Quick(); + + // Handle key event + Utils::Hook(0x63C5BC, UIFeeder::HandleKeyStub, HOOK_CALL).Install()->Quick(); + + // Mouse select check + Utils::Hook(0x639D31, UIFeeder::MouseSelectStub, HOOK_CALL).Install()->Quick(); + + // Play mouse over sound check + Utils::Hook(0x639D66, UIFeeder::PlaySoundStub, HOOK_CALL).Install()->Quick(); + + // some thing overwriting feeder 2's data + Utils::Hook::Set(0x4A06A9, 0xEB); + } + + UIFeeder::~UIFeeder() + { + UIFeeder::Feeders.clear(); + } +} diff --git a/iw4/Components/Feeder.hpp b/iw4/Components/UIFeeder.hpp similarity index 87% rename from iw4/Components/Feeder.hpp rename to iw4/Components/UIFeeder.hpp index 26cbd658..dc6cd950 100644 --- a/iw4/Components/Feeder.hpp +++ b/iw4/Components/UIFeeder.hpp @@ -1,6 +1,6 @@ namespace Components { - class Feeder : public Component + class UIFeeder : public Component { public: typedef int(__cdecl * GetItemCount_t)(); @@ -14,16 +14,16 @@ namespace Components Select_t Select; }; - Feeder(); - ~Feeder(); - const char* GetName() { return "Feeder"; }; + UIFeeder(); + ~UIFeeder(); + const char* GetName() { return "UIFeeder"; }; static void Add(float feeder, GetItemCount_t itemCountCb, GetItemText_t itemTextCb, Select_t selectCb); private: struct Container { - float Num; + float Feeder; int Index; int Column; }; diff --git a/iw4/Components/UIScript.cpp b/iw4/Components/UIScript.cpp new file mode 100644 index 00000000..218640f3 --- /dev/null +++ b/iw4/Components/UIScript.cpp @@ -0,0 +1,110 @@ +#include "..\STDInclude.hpp" + +namespace Components +{ + std::map UIScript::UIScripts; + + template<> int UIScript::Token::Get() + { + if (this->IsValid()) + { + return atoi(this->token); + } + + return 0; + } + + template<> char* UIScript::Token::Get() + { + if (this->IsValid()) + { + return this->token; + } + + return ""; + } + + template<> const char* UIScript::Token::Get() + { + return this->Get(); + } + + template<> std::string UIScript::Token::Get() + { + return this->Get(); + } + + bool UIScript::Token::IsValid() + { + return (token && token[0]); + } + + void UIScript::Token::Parse(const char** args) + { + if (args) + { + this->token = Game::Com_ParseExt(args); + } + } + + void UIScript::Add(std::string name, UIScript::Callback callback) + { + UIScript::UIScripts[name] = callback; + } + + void UIScript::Add(std::string name, UIScript::CallbackRaw callback) + { + UIScript::Add(name, reinterpret_cast(callback)); + } + + bool UIScript::RunMenuScript(const char* name, const char** args) + { + if (UIScript::UIScripts.find(name) != UIScript::UIScripts.end()) + { + UIScript::UIScripts[name](UIScript::Token(args)); + return true; + } + + return false; + } + + void __declspec(naked) UIScript::RunMenuScriptStub() + { + __asm + { + mov eax, esp + add eax, 8h + mov edx, eax // UIScript name + mov eax, [esp + 0C10h] // UIScript args + + push eax + push edx + call UIScript::RunMenuScript + add esp, 8h + + test eax, eax + jz continue + + // if returned + pop edi + pop esi + add esp, 0C00h + retn + + continue: + mov eax, 45ED00h + jmp eax + } + } + + UIScript::UIScript() + { + // Install handler + Utils::Hook::Set(0x45EC5B, (DWORD)UIScript::RunMenuScriptStub - 0x45EC59 - 6); + } + + UIScript::~UIScript() + { + UIScript::UIScripts.clear(); + } +} diff --git a/iw4/Components/UIScript.hpp b/iw4/Components/UIScript.hpp new file mode 100644 index 00000000..49318195 --- /dev/null +++ b/iw4/Components/UIScript.hpp @@ -0,0 +1,39 @@ +namespace Components +{ + class UIScript : public Component + { + public: + UIScript(); + ~UIScript(); + const char* GetName() { return "UIScript"; }; + + class Token + { + public: + Token(const char** args) : token(0) { this->Parse(args); }; + Token(const Token &obj) { this->token = obj.token; }; + + template T Get(); + bool IsValid(); + + + private: + char* token; + + void Parse(const char** args); + }; + + typedef void(*Callback)(Token token); + typedef void(*CallbackRaw)(); + + static void Add(std::string name, Callback callback); + static void Add(std::string name, CallbackRaw callback); + + private: + + static bool RunMenuScript(const char* name, const char** args); + static void RunMenuScriptStub(); + + static std::map UIScripts; + }; +} diff --git a/iw4/Game/Functions.cpp b/iw4/Game/Functions.cpp index 42033f55..c11262e0 100644 --- a/iw4/Game/Functions.cpp +++ b/iw4/Game/Functions.cpp @@ -13,6 +13,7 @@ namespace Game Com_Error_t Com_Error = (Com_Error_t)0x4B22D0; Com_Printf_t Com_Printf = (Com_Printf_t)0x402500; Com_Milliseconds_t Com_Milliseconds = (Com_Milliseconds_t)0x42A660; + Com_ParseExt_t Com_ParseExt = (Com_ParseExt_t)0x474D60; DB_FindXAssetHeader_t DB_FindXAssetHeader = (DB_FindXAssetHeader_t)0x407930; DB_GetXAssetNameHandler_t* DB_GetXAssetNameHandlers = (DB_GetXAssetNameHandler_t*)0x799328; diff --git a/iw4/Game/Functions.hpp b/iw4/Game/Functions.hpp index 2c3ef255..d702804c 100644 --- a/iw4/Game/Functions.hpp +++ b/iw4/Game/Functions.hpp @@ -24,6 +24,9 @@ namespace Game typedef int(__cdecl * Com_Milliseconds_t)(void); extern Com_Milliseconds_t Com_Milliseconds; + typedef char* (__cdecl * Com_ParseExt_t)(const char**); + extern Com_ParseExt_t Com_ParseExt; + typedef XAssetHeader (__cdecl * DB_FindXAssetHeader_t)(XAssetType type, const char* filename); extern DB_FindXAssetHeader_t DB_FindXAssetHeader; diff --git a/iw4/Main.cpp b/iw4/Main.cpp index b3cc32f9..71f917c5 100644 --- a/iw4/Main.cpp +++ b/iw4/Main.cpp @@ -12,13 +12,13 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser DWORD oldProtect; VirtualProtect(GetModuleHandle(NULL), 0x6C73000, PAGE_EXECUTE_READWRITE, &oldProtect); - EntryPointHook.Initialize(0x6BAC0F, static_cast([] () + EntryPointHook.Initialize(0x6BAC0F, [] () { EntryPointHook.Uninstall(); Components::Loader::Initialize(); __asm jmp EntryPointHook.Place - }))->Install(); + })->Install(); } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { diff --git a/iw4/Utils/Hooking.cpp b/iw4/Utils/Hooking.cpp index 95bfd11b..64cb4b74 100644 --- a/iw4/Utils/Hooking.cpp +++ b/iw4/Utils/Hooking.cpp @@ -10,6 +10,11 @@ namespace Utils } } + Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump) + { + return Hook::Initialize(place, (void*)stub, useJump); + } + Hook* Hook::Initialize(DWORD place, void* stub, bool useJump) { return Hook::Initialize((void*)place, stub, useJump); diff --git a/iw4/Utils/Hooking.hpp b/iw4/Utils/Hooking.hpp index bad657c9..2dbe33ff 100644 --- a/iw4/Utils/Hooking.hpp +++ b/iw4/Utils/Hooking.hpp @@ -16,6 +16,7 @@ namespace Utils Hook* Initialize(void* place, void* stub, bool useJump = true); Hook* Initialize(DWORD place, void* stub, bool useJump = true); + Hook* Initialize(DWORD place, void(*stub)(), bool useJump = true); // For lambdas Hook* Install(); Hook* Uninstall(); diff --git a/iw4/iw4.vcxproj b/iw4/iw4.vcxproj index 524a18fd..1089b3c3 100644 --- a/iw4/iw4.vcxproj +++ b/iw4/iw4.vcxproj @@ -61,7 +61,6 @@ - @@ -77,6 +76,8 @@ + + @@ -101,7 +102,6 @@ - @@ -117,6 +117,8 @@ + + diff --git a/iw4/iw4.vcxproj.filters b/iw4/iw4.vcxproj.filters index 7cb1e11c..17fde619 100644 --- a/iw4/iw4.vcxproj.filters +++ b/iw4/iw4.vcxproj.filters @@ -134,10 +134,13 @@ Source\Components\Modules - + Source\Components\Modules - + + Source\Components\Modules + + Source\Components\Modules @@ -250,10 +253,13 @@ Source\Components\Modules - + Source\Components\Modules - + + Source\Components\Modules + + Source\Components\Modules