Party and connect.
This commit is contained in:
@ -36,6 +36,20 @@ namespace Components
|
||||
Game::Cmd_AddCommand(name, Command::MainCallback, Command::Allocate(), 0);
|
||||
}
|
||||
|
||||
void Command::Execute(std::string command, bool sync)
|
||||
{
|
||||
command.append("\n"); // Make sure it's terminated
|
||||
|
||||
if (sync)
|
||||
{
|
||||
Game::Cmd_ExecuteSingleCommand(0, 0, command.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
Game::Cbuf_AddText(0, command.data());
|
||||
}
|
||||
}
|
||||
|
||||
Game::cmd_function_t* Command::Allocate()
|
||||
{
|
||||
Game::cmd_function_t* cmd = new Game::cmd_function_t;
|
||||
|
@ -23,7 +23,8 @@ namespace Components
|
||||
const char* GetName() { return "Command"; };
|
||||
|
||||
static void Add(const char* name, Callback callback);
|
||||
static int ArgCount();
|
||||
|
||||
static void Execute(std::string command, bool sync = true);
|
||||
|
||||
private:
|
||||
static Game::cmd_function_t* Allocate();
|
||||
|
@ -8,7 +8,9 @@ namespace Components
|
||||
|
||||
if (!this->dvar)
|
||||
{
|
||||
// Register the dvar?
|
||||
// Quick-register the dvar
|
||||
Game::SetConsole(dvarName.data(), "");
|
||||
this->dvar = Game::Dvar_FindVar(dvarName.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ namespace Components
|
||||
Var(const Var &obj) { this->dvar = obj.dvar; };
|
||||
Var(Game::dvar_t* _dvar) : dvar(_dvar) {};
|
||||
Var(std::string dvarName);
|
||||
Var(std::string dvarName, std::string value);
|
||||
|
||||
template<typename T> T Get();
|
||||
|
||||
|
@ -8,6 +8,7 @@ namespace Components
|
||||
{
|
||||
Loader::Register(new Dvar());
|
||||
Loader::Register(new Menus());
|
||||
Loader::Register(new Party());
|
||||
Loader::Register(new Colors());
|
||||
Loader::Register(new Logger());
|
||||
Loader::Register(new Window());
|
||||
|
@ -28,6 +28,7 @@ namespace Components
|
||||
#include "Command.hpp"
|
||||
#include "Console.hpp"
|
||||
#include "Network.hpp"
|
||||
#include "Party.hpp" // Destroys the order, but requires network classes :D
|
||||
#include "RawFiles.hpp"
|
||||
#include "Renderer.hpp"
|
||||
#include "FastFiles.hpp"
|
||||
|
@ -116,7 +116,7 @@ namespace Components
|
||||
Game::pc_token_t token;
|
||||
Game::keywordHash_t *key;
|
||||
|
||||
if (!Menus::ReadToken(handle, &token) || token.string[0] != '{')
|
||||
if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] != '{')
|
||||
{
|
||||
return menu;
|
||||
}
|
||||
@ -125,7 +125,7 @@ namespace Components
|
||||
{
|
||||
ZeroMemory(&token, sizeof(token));
|
||||
|
||||
if (!Menus::ReadToken(handle, &token))
|
||||
if (!Game::PC_ReadTokenHandle(handle, &token))
|
||||
{
|
||||
Game::PC_SourceError(handle, "end of file inside menu\n");
|
||||
break; // Fail
|
||||
@ -153,40 +153,11 @@ namespace Components
|
||||
}
|
||||
}
|
||||
|
||||
OutputDebugStringA(Utils::VA("%X %s", menu->window.name, menu->window.name));
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
int Menus::ReadToken(int handle, Game::pc_token_t *pc_token)
|
||||
{
|
||||
Game::token_t token;
|
||||
int ret;
|
||||
|
||||
if (!Menus::IsValidSourceHandle(handle)) return 0;
|
||||
|
||||
ret = Game::PC_ReadToken(Game::sourceFiles[handle], &token);
|
||||
strcpy(pc_token->string, token.string);
|
||||
pc_token->type = token.type;
|
||||
pc_token->subtype = token.subtype;
|
||||
pc_token->intvalue = token.intvalue;
|
||||
pc_token->floatvalue = (float)token.floatvalue;
|
||||
|
||||
if (pc_token->type == TT_STRING)
|
||||
{
|
||||
// StripDoubleQuotes
|
||||
char *string = pc_token->string;
|
||||
if (*string == '\"')
|
||||
{
|
||||
strcpy(string, string + 1);
|
||||
}
|
||||
if (string[strlen(string) - 1] == '\"')
|
||||
{
|
||||
string[strlen(string) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<Game::menuDef_t*> Menus::LoadMenu(Game::menuDef_t* menudef)
|
||||
{
|
||||
std::vector<Game::menuDef_t*> menus;
|
||||
@ -206,14 +177,14 @@ namespace Components
|
||||
{
|
||||
ZeroMemory(&token, sizeof(token));
|
||||
|
||||
if (!Menus::ReadToken(handle, &token) || token.string[0] == '}')
|
||||
if (!Game::PC_ReadTokenHandle(handle, &token) || token.string[0] == '}')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!_stricmp(token.string, "loadmenu"))
|
||||
{
|
||||
Menus::ReadToken(handle, &token);
|
||||
Game::PC_ReadTokenHandle(handle, &token);
|
||||
|
||||
// Ugly, but does the job ;)
|
||||
Game::menuDef_t _temp;
|
||||
@ -250,6 +221,11 @@ namespace Components
|
||||
|
||||
for (int i = 0; i < menuList->menuCount; i++)
|
||||
{
|
||||
if (!menuList->menus[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<Game::menuDef_t*> newMenus = Menus::LoadMenu(menuList->menus[i]);
|
||||
|
||||
for (auto newMenu : newMenus)
|
||||
@ -409,19 +385,16 @@ namespace Components
|
||||
|
||||
Game::XAssetHeader Menus::MenuFileLoad(Game::XAssetType type, const char* filename)
|
||||
{
|
||||
Game::XAssetHeader header = { 0 };
|
||||
Game::XAssetHeader header = { 0 };
|
||||
|
||||
// Check if we already loaded it
|
||||
for (auto menuList : Menus::MenuListList)
|
||||
{
|
||||
if (!_stricmp(menuList->name, filename))
|
||||
{
|
||||
// Free it!
|
||||
// Seems like the game deallocated half of it :P
|
||||
// Free it, seems like the game deallocated it
|
||||
Menus::RemoveMenuList(menuList);
|
||||
break;
|
||||
//header.menuList = menuList;
|
||||
//return header;
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +404,7 @@ namespace Components
|
||||
if (menuList)
|
||||
{
|
||||
// Don't parse scriptmenus for now!
|
||||
if (!Utils::EndsWith(filename, ".menu"))
|
||||
if (strcmp(menuList->menus[0]->window.name, "default_menu") && !Utils::EndsWith(filename, ".menu"))
|
||||
{
|
||||
header.menuList = Menus::LoadMenuList(menuList);
|
||||
}
|
||||
@ -440,17 +413,31 @@ namespace Components
|
||||
return header;
|
||||
}
|
||||
|
||||
void Menus::AddMenuListHook(int dc, Game::MenuList *menuList, int close)
|
||||
{
|
||||
Game::MenuList* menus = Game::DB_FindXAssetHeader(Game::XAssetType::ASSET_TYPE_MENUFILE, "ui_mp/menus.txt").menuList;
|
||||
|
||||
Game::UI_AddMenuList(dc, menus, close);
|
||||
Game::UI_AddMenuList(dc, menuList, close);
|
||||
}
|
||||
|
||||
Menus::Menus()
|
||||
{
|
||||
AssetHandler::On(Game::XAssetType::ASSET_TYPE_MENUFILE, Menus::MenuFileLoad);
|
||||
//Utils::Hook(0x63FE80, Menus::MenuFileLoad, HOOK_JUMP).Install()->Quick();
|
||||
|
||||
// Load menus ingame
|
||||
//Utils::Hook(0x41C178, Menus::AddMenuListHook, HOOK_CALL).Install()->Quick();
|
||||
|
||||
// disable the 2 new tokens in ItemParse_rect
|
||||
Utils::Hook::Set<BYTE>(0x640693, 0xEB);
|
||||
|
||||
// don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail)
|
||||
Utils::Hook::Nop(0x453406, 5);
|
||||
|
||||
//make Com_Error and similar go back to main_text instead of menu_xboxlive.
|
||||
strcpy((char*)0x6FC790, "main_text");
|
||||
|
||||
Command::Add("openmenu", [] (Command::Params params)
|
||||
{
|
||||
if (params.Length() != 2)
|
||||
|
@ -9,6 +9,8 @@ namespace Components
|
||||
~Menus();
|
||||
const char* GetName() { return "Menus"; };
|
||||
|
||||
static void FreeEverything();
|
||||
|
||||
private:
|
||||
static std::vector<Game::menuDef_t*> MenuList;
|
||||
static std::vector<Game::MenuList*> MenuListList;
|
||||
@ -23,8 +25,6 @@ namespace Components
|
||||
static int ReserveSourceHandle();
|
||||
static bool IsValidSourceHandle(int handle);
|
||||
|
||||
static int ReadToken(int handle, Game::pc_token_t *pc_token);
|
||||
|
||||
static Game::menuDef_t* ParseMenu(int handle);
|
||||
|
||||
static void FreeMenuSource(int handle);
|
||||
@ -35,7 +35,7 @@ namespace Components
|
||||
static void RemoveMenu(Game::menuDef_t* menudef);
|
||||
static void RemoveMenuList(Game::MenuList* menuList);
|
||||
|
||||
static void FreeEverything();
|
||||
static void AddMenuListHook(int dc, Game::MenuList *menuList, int close);
|
||||
|
||||
// Ugly!
|
||||
static int KeywordHash(char* key);
|
||||
|
@ -60,7 +60,8 @@ namespace Components
|
||||
{
|
||||
if (Network::PacketHandlers.find(Network::SelectedPacket) != Network::PacketHandlers.end())
|
||||
{
|
||||
Network::PacketHandlers[Network::SelectedPacket](from, msg);
|
||||
size_t offset = Network::SelectedPacket.size() + 4 + 1;
|
||||
Network::PacketHandlers[Network::SelectedPacket](from, std::string(msg->data + offset, msg->cursize - offset));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -109,48 +110,6 @@ namespace Components
|
||||
|
||||
// Install packet deploy hook
|
||||
Utils::Hook::Set<int>(0x5AA715, (DWORD)Network::DeployPacketStub - 0x5AA713 - 6);
|
||||
|
||||
Network::Handle("infoResponse", [] (Address address, Game::msg_t* message)
|
||||
{
|
||||
OutputDebugStringA(Utils::VA("Inforesponse received: %s %s!", address.GetString(), message->data));
|
||||
});
|
||||
|
||||
Network::Handle("getInfo", [] (Address address, Game::msg_t* message)
|
||||
{
|
||||
OutputDebugStringA(Utils::VA("getinfo received: %s!", address.GetString()));
|
||||
|
||||
int clientCount = 0;
|
||||
|
||||
for (int i = 0; i < *Game::svs_numclients; i++)
|
||||
{
|
||||
if (Game::svs_clients[i].state >= 3)
|
||||
{
|
||||
clientCount++;
|
||||
}
|
||||
}
|
||||
|
||||
auto data = std::string(message->data);
|
||||
auto challenge = data.substr(data.find_first_of(" \n") + 1);
|
||||
challenge = challenge.substr(0, challenge.find_first_of(" \n"));
|
||||
|
||||
Utils::InfoString info;
|
||||
info.Set("challenge", challenge.data()); // TODO: Fill!
|
||||
info.Set("gamename", "IW4");
|
||||
info.Set("hostname", Dvar::Var("sv_hostname").Get<const char*>());
|
||||
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
||||
info.Set("gametype", Dvar::Var("g_gametype").Get<const char*>());
|
||||
info.Set("fs_game", Dvar::Var("fs_game").Get<const char*>());
|
||||
info.Set("xuid", Utils::VA("%llX", Steam::SteamUser()->GetSteamID().m_Bits));
|
||||
info.Set("clients", Utils::VA("%i", clientCount));
|
||||
info.Set("sv_maxclients", Utils::VA("%i", *Game::svs_numclients));
|
||||
|
||||
Network::Send(Game::NS_CLIENT, address, Utils::VA("infoResponse\n%s\n", info.Build().data()));
|
||||
});
|
||||
|
||||
Command::Add("zob", [] (Command::Params params)
|
||||
{
|
||||
Network::Send(Game::NS_CLIENT, Network::Address("localhost:28960"), "getinfo xxx\n");
|
||||
});
|
||||
}
|
||||
|
||||
Network::~Network()
|
||||
|
@ -24,7 +24,7 @@ namespace Components
|
||||
Game::netadr_t address;
|
||||
};
|
||||
|
||||
typedef void(*Callback)(Address address, Game::msg_t* message);
|
||||
typedef void(*Callback)(Address address, std::string data);
|
||||
|
||||
Network();
|
||||
~Network();
|
||||
|
133
iw4/Components/Party.cpp
Normal file
133
iw4/Components/Party.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "..\STDInclude.hpp"
|
||||
|
||||
namespace Components
|
||||
{
|
||||
Party::JoinContainer Party::Container;
|
||||
|
||||
void Party::Connect(Network::Address target)
|
||||
{
|
||||
Party::Container.Valid = true;
|
||||
Party::Container.JoinTime = Game::Com_Milliseconds();
|
||||
Party::Container.Target = target;
|
||||
Party::Container.Challenge = Utils::VA("%X", Party::Container.JoinTime);
|
||||
|
||||
Network::Send(Game::NS_CLIENT, Party::Container.Target, Utils::VA("getinfo %s\n", Party::Container.Challenge.data()));
|
||||
|
||||
Command::Execute("openmenu popup_reconnectingtoparty");
|
||||
}
|
||||
|
||||
Party::Party()
|
||||
{
|
||||
// various changes to SV_DirectConnect-y stuff to allow non-party joinees
|
||||
Utils::Hook::Set<WORD>(0x460D96, 0x90E9);
|
||||
Utils::Hook::Set<BYTE>(0x460F0A, 0xEB);
|
||||
Utils::Hook::Set<BYTE>(0x401CA4, 0xEB);
|
||||
Utils::Hook::Set<BYTE>(0x401C15, 0xEB);
|
||||
|
||||
// disable configstring checksum matching (it's unreliable at most)
|
||||
Utils::Hook::Set<BYTE>(0x4A75A7, 0xEB); // SV_SpawnServer
|
||||
Utils::Hook::Set<BYTE>(0x5AC2CF, 0xEB); // CL_ParseGamestate
|
||||
Utils::Hook::Set<BYTE>(0x5AC2C3, 0xEB); // CL_ParseGamestate
|
||||
|
||||
Command::Add("connect", [] (Command::Params params)
|
||||
{
|
||||
if (params.Length() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Party::Connect(Network::Address(params[1]));
|
||||
});
|
||||
|
||||
Renderer::OnFrame([] ()
|
||||
{
|
||||
if (!Party::Container.Valid) return;
|
||||
|
||||
if ((Game::Com_Milliseconds() - Party::Container.JoinTime) > 5000)
|
||||
{
|
||||
Party::Container.Valid = false;
|
||||
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Dvar::Var("partyend_reason").Set("Server connection timed out.");
|
||||
Command::Execute("openmenu menu_xboxlive_partyended");
|
||||
}
|
||||
});
|
||||
|
||||
// Basic info handler
|
||||
Network::Handle("getInfo", [] (Network::Address address, std::string data)
|
||||
{
|
||||
int clientCount = 0;
|
||||
|
||||
for (int i = 0; i < *Game::svs_numclients; i++)
|
||||
{
|
||||
if (Game::svs_clients[i].state >= 3)
|
||||
{
|
||||
clientCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Utils::InfoString info;
|
||||
info.Set("challenge", data.substr(0, data.find_first_of("\n")).data());
|
||||
info.Set("gamename", "IW4");
|
||||
info.Set("hostname", Dvar::Var("sv_hostname").Get<const char*>());
|
||||
info.Set("mapname", Dvar::Var("mapname").Get<const char*>());
|
||||
info.Set("gametype", Dvar::Var("g_gametype").Get<const char*>());
|
||||
info.Set("fs_game", Dvar::Var("fs_game").Get<const char*>());
|
||||
info.Set("xuid", Utils::VA("%llX", Steam::SteamUser()->GetSteamID().m_Bits));
|
||||
info.Set("clients", Utils::VA("%i", clientCount));
|
||||
info.Set("sv_maxclients", Utils::VA("%i", *Game::svs_numclients));
|
||||
|
||||
Network::Send(Game::NS_CLIENT, address, Utils::VA("infoResponse\n%s\n", info.Build().data()));
|
||||
});
|
||||
|
||||
Network::Handle("infoResponse", [] (Network::Address address, std::string data)
|
||||
{
|
||||
// Handle connection
|
||||
if (Party::Container.Valid)
|
||||
{
|
||||
if (Party::Container.Target == address)
|
||||
{
|
||||
// Invalidate handler for future packets
|
||||
Party::Container.Valid = false;
|
||||
|
||||
Utils::InfoString info(data);
|
||||
|
||||
OutputDebugStringA(data.data());
|
||||
|
||||
if (info.Get("challenge") != Party::Container.Challenge)
|
||||
{
|
||||
OutputDebugStringA(Utils::VA("\"%s\" vs. \"%s\"", info.Get("challenge").data(), Party::Container.Challenge.data()));
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Dvar::Var("partyend_reason").Set("Invalid join response: Challenge mismatch.");
|
||||
Command::Execute("openmenu menu_xboxlive_partyended");
|
||||
}
|
||||
else if (atoi(info.Get("clients").data()) >= atoi(info.Get("sv_maxclients").data()))
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Dvar::Var("partyend_reason").Set("@EXE_SERVERISFULL");
|
||||
Command::Execute("openmenu menu_xboxlive_partyended");
|
||||
}
|
||||
else if (info.Get("mapname") == "" || info.Get("gametype") == "")
|
||||
{
|
||||
Command::Execute("closemenu popup_reconnectingtoparty");
|
||||
Dvar::Var("partyend_reason").Set("Invalid map or gametype.");
|
||||
Command::Execute("openmenu menu_xboxlive_partyended");
|
||||
}
|
||||
else
|
||||
{
|
||||
Dvar::Var("xblive_privatematch").Set(1);
|
||||
Game::Menus_CloseAll(0x62E2858);
|
||||
|
||||
char xnaddr[32];
|
||||
Game::CL_ConnectFromParty(0, xnaddr, *address.Get(), 0, 0, info.Get("mapname").data(), info.Get("gametype").data());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Party::~Party()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
23
iw4/Components/Party.hpp
Normal file
23
iw4/Components/Party.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
namespace Components
|
||||
{
|
||||
class Party : public Component
|
||||
{
|
||||
public:
|
||||
Party();
|
||||
~Party();
|
||||
const char* GetName() { return "Party"; };
|
||||
|
||||
static void Connect(Network::Address target);
|
||||
|
||||
private:
|
||||
struct JoinContainer
|
||||
{
|
||||
Network::Address Target;
|
||||
std::string Challenge;
|
||||
DWORD JoinTime;
|
||||
bool Valid;
|
||||
};
|
||||
|
||||
static JoinContainer Container;
|
||||
};
|
||||
}
|
@ -2,6 +2,12 @@
|
||||
|
||||
namespace Components
|
||||
{
|
||||
__int64* QuickPatch::GetStatsID()
|
||||
{
|
||||
static __int64 id = 0x110000100001337;
|
||||
return &id;
|
||||
}
|
||||
|
||||
QuickPatch::QuickPatch()
|
||||
{
|
||||
// remove system pre-init stuff (improper quit, disk full)
|
||||
@ -54,6 +60,16 @@ namespace Components
|
||||
// default sv_pure to 0
|
||||
Utils::Hook::Set<BYTE>(0x4D3A74, 0);
|
||||
|
||||
// Force debug logging
|
||||
Utils::Hook::Nop(0x4AA89F, 2);
|
||||
Utils::Hook::Nop(0x4AA8A1, 6);
|
||||
|
||||
// Patch stats steamid
|
||||
Utils::Hook::Nop(0x682EBF, 20);
|
||||
Utils::Hook::Nop(0x6830B1, 20);
|
||||
Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
||||
Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick();
|
||||
|
||||
// Why?
|
||||
Game::ReallocateAssetPool(Game::XAssetType::ASSET_TYPE_WEAPON, 2400);
|
||||
}
|
||||
|
@ -5,5 +5,8 @@ namespace Components
|
||||
public:
|
||||
QuickPatch();
|
||||
const char* GetName() { return "QuickPatch"; };
|
||||
|
||||
private:
|
||||
static _int64* GetStatsID();
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user