Party and connect.

This commit is contained in:
momo5502
2015-12-25 21:42:35 +01:00
parent c6e3695228
commit 6fb6a1e977
22 changed files with 345 additions and 111 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,5 +5,8 @@ namespace Components
public:
QuickPatch();
const char* GetName() { return "QuickPatch"; };
private:
static _int64* GetStatsID();
};
}