Merge pull request #456 from diamante0018/develop

[Vote/UI] Add UI Script Handlers
This commit is contained in:
Dss0 2022-08-24 16:48:43 +02:00 committed by GitHub
commit d3a2604e61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 310 additions and 194 deletions

View File

@ -472,7 +472,7 @@ namespace Components
});
}
UIScript::Add("security_increase_cancel", [](UIScript::Token)
UIScript::Add("security_increase_cancel", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Auth::TokenContainer.cancel = true;
Logger::Print("Token incrementation process canceled!\n");

View File

@ -909,7 +909,7 @@ namespace Components
Dvar::Register<const char*>("ui_dl_transRate", "", Game::DVAR_NONE, "");
}, Scheduler::Pipeline::MAIN);
UIScript::Add("mod_download_cancel", [](UIScript::Token)
UIScript::Add("mod_download_cancel", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Download::CLDownload.clear();
});

View File

@ -604,12 +604,12 @@ namespace Components
// Show blue icons on the minimap
Utils::Hook(0x493130, Friends::IsClientInParty, HOOK_JUMP).install()->quick();
UIScript::Add("LoadFriends", [](UIScript::Token)
UIScript::Add("LoadFriends", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Friends::UpdateFriends();
});
UIScript::Add("JoinFriend", [](UIScript::Token)
UIScript::Add("JoinFriend", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
if (Friends::CurrentFriend >= Friends::FriendsList.size()) return;

View File

@ -58,6 +58,15 @@ namespace Components
}
}
bool MapRotation::RotationData::contains(const std::string& key, const std::string& value) const
{
return std::ranges::any_of(this->rotationEntries_,
[&](const auto& entry)
{
return entry.first == key && entry.second == value;
});
}
nlohmann::json MapRotation::RotationData::to_json() const
{
std::vector<std::string> mapVector;
@ -109,6 +118,17 @@ namespace Components
Logger::Debug("DedicatedRotation size after parsing is '{}'", DedicatedRotation.getEntriesSize());
}
void MapRotation::LoadMapRotation()
{
const std::string mapRotation = (*Game::sv_mapRotation)->current.string;
// People may have sv_mapRotation empty because they only use 'addMap' or 'addGametype'
if (!mapRotation.empty())
{
Logger::Debug("sv_mapRotation is not empty. Parsing...");
LoadRotation(mapRotation);
}
}
void MapRotation::AddMapRotationCommands()
{
Command::Add("addMap", [](Command::Params* params)
@ -134,6 +154,11 @@ namespace Components
});
}
bool MapRotation::Contains(const std::string& key, const std::string& value)
{
return DedicatedRotation.contains(key, value);
}
bool MapRotation::ShouldRotate()
{
if (!Dedicated::IsEnabled() && SVDontRotate.get<bool>())
@ -276,14 +301,7 @@ namespace Components
return;
}
const std::string mapRotation = (*Game::sv_mapRotation)->current.string;
// People may have sv_mapRotation empty because they only use 'addMap' or 'addGametype'
if (!mapRotation.empty())
{
Logger::Debug("sv_mapRotation is not empty. Parsing...");
LoadRotation(mapRotation);
}
LoadMapRotation();
if (DedicatedRotation.getEntriesSize() == 0)
{
Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*Game::sv_mapRotation)->name);

View File

@ -7,6 +7,8 @@ namespace Components
public:
MapRotation();
static bool Contains(const std::string& key, const std::string& value);
bool unitTest() override;
private:
@ -33,7 +35,8 @@ namespace Components
void parse(const std::string& data);
// Json11 Implicit constructor
[[nodiscard]] bool contains(const std::string& key, const std::string& value) const;
[[nodiscard]] nlohmann::json to_json() const;
private:
@ -50,6 +53,7 @@ namespace Components
static RotationData DedicatedRotation;
static void LoadRotation(const std::string& data);
static void LoadMapRotation();
// Use these commands before SV_MapRotate_f is called
static void AddMapRotationCommands();

View File

@ -768,7 +768,7 @@ namespace Components
Maps::UpdateDlcStatus();
UIScript::Add("downloadDLC", [](UIScript::Token token)
UIScript::Add("downloadDLC", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
int dlc = token.get<int>();

View File

@ -785,80 +785,80 @@ namespace Components
}
}, HOOK_CALL).install()->quick();
// Intercept menu painting
Utils::Hook(0x4FFBDF, Menus::IsMenuVisible, HOOK_CALL).install()->quick();
// Intercept menu painting
Utils::Hook(0x4FFBDF, Menus::IsMenuVisible, HOOK_CALL).install()->quick();
// disable the 2 new tokens in ItemParse_rect
Utils::Hook::Set<BYTE>(0x640693, 0xEB);
// 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);
// 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.
Utils::Hook::SetString(0x6FC790, "main_text");
// make Com_Error and similar go back to main_text instead of menu_xboxlive.
Utils::Hook::SetString(0x6FC790, "main_text");
Command::Add("openmenu", [](Command::Params* params)
Command::Add("openmenu", [](Command::Params* params)
{
if (params->size() != 2)
{
if (params->size() != 2)
{
Logger::Print("USAGE: openmenu <menu name>\n");
return;
}
Logger::Print("USAGE: openmenu <menu name>\n");
return;
}
// Not quite sure if we want to do this if we're not ingame, but it's only needed for ingame menus.
if (Dvar::Var("cl_ingame").get<bool>())
{
Game::Key_SetCatcher(0, 16);
}
Game::Menus_OpenByName(Game::uiContext, params->get(1));
});
Command::Add("reloadmenus", [](Command::Params*)
// Not quite sure if we want to do this if we're not ingame, but it's only needed for ingame menus.
if (Dvar::Var("cl_ingame").get<bool>())
{
// Close all menus
Game::Menus_CloseAll(Game::uiContext);
Game::Key_SetCatcher(0, 16);
}
// Free custom menus
Menus::FreeEverything();
Game::Menus_OpenByName(Game::uiContext, params->get(1));
});
// Only disconnect if in-game, context is updated automatically!
if (Game::CL_IsCgameInitialized())
{
Game::Cbuf_AddText(0, "disconnect\n");
}
else
{
// Reinitialize ui context
Utils::Hook::Call<void()>(0x401700)();
Command::Add("reloadmenus", [](Command::Params*)
{
// Close all menus
Game::Menus_CloseAll(Game::uiContext);
// Reopen main menu
Game::Menus_OpenByName(Game::uiContext, "main_text");
}
});
// Free custom menus
Menus::FreeEverything();
Command::Add("mp_QuickMessage", [](Command::Params*)
// Only disconnect if in-game, context is updated automatically!
if (Game::CL_IsCgameInitialized())
{
Command::Execute("openmenu quickmessage");
});
Game::Cbuf_AddText(0, "disconnect\n");
}
else
{
// Reinitialize ui context
Utils::Hook::Call<void()>(0x401700)();
// Define custom menus here
Menus::Add("ui_mp/changelog.menu");
Menus::Add("ui_mp/theater_menu.menu");
Menus::Add("ui_mp/pc_options_multi.menu");
Menus::Add("ui_mp/pc_options_game.menu");
Menus::Add("ui_mp/pc_options_gamepad.menu");
Menus::Add("ui_mp/stats_reset.menu");
Menus::Add("ui_mp/stats_unlock.menu");
Menus::Add("ui_mp/security_increase_popmenu.menu");
Menus::Add("ui_mp/mod_download_popmenu.menu");
Menus::Add("ui_mp/popup_friends.menu");
Menus::Add("ui_mp/menu_first_launch.menu");
Menus::Add("ui_mp/startup_messages.menu");
Menus::Add("ui_mp/iw4x_credits.menu");
Menus::Add("ui_mp/resetclass.menu");
Menus::Add("ui_mp/popup_customtitle.menu");
Menus::Add("ui_mp/popup_customclan.menu");
// Reopen main menu
Game::Menus_OpenByName(Game::uiContext, "main_text");
}
});
Command::Add("mp_QuickMessage", [](Command::Params*)
{
Command::Execute("openmenu quickmessage");
});
// Define custom menus here
Menus::Add("ui_mp/changelog.menu");
Menus::Add("ui_mp/theater_menu.menu");
Menus::Add("ui_mp/pc_options_multi.menu");
Menus::Add("ui_mp/pc_options_game.menu");
Menus::Add("ui_mp/pc_options_gamepad.menu");
Menus::Add("ui_mp/stats_reset.menu");
Menus::Add("ui_mp/stats_unlock.menu");
Menus::Add("ui_mp/security_increase_popmenu.menu");
Menus::Add("ui_mp/mod_download_popmenu.menu");
Menus::Add("ui_mp/popup_friends.menu");
Menus::Add("ui_mp/menu_first_launch.menu");
Menus::Add("ui_mp/startup_messages.menu");
Menus::Add("ui_mp/iw4x_credits.menu");
Menus::Add("ui_mp/resetclass.menu");
Menus::Add("ui_mp/popup_customtitle.menu");
Menus::Add("ui_mp/popup_customclan.menu");
}
Menus::~Menus()

View File

@ -40,7 +40,7 @@ namespace Components
ModList::CurrentMod = index;
}
void ModList::UIScript_LoadMods(UIScript::Token)
void ModList::UIScript_LoadMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
auto folder = Dvar::Var("fs_basepath").get<std::string>() + "\\mods";
Logger::Debug("Searching for mods in {}...", folder);
@ -48,7 +48,7 @@ namespace Components
Logger::Debug("Found {} mods!", ModList::Mods.size());
}
void ModList::UIScript_RunMod(UIScript::Token)
void ModList::UIScript_RunMod([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (ModList::CurrentMod < ModList::Mods.size())
{
@ -56,7 +56,7 @@ namespace Components
}
}
void ModList::UIScript_ClearMods(UIScript::Token)
void ModList::UIScript_ClearMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
auto fsGame = Dvar::Var("fs_game");
fsGame.set("");

View File

@ -18,8 +18,8 @@ namespace Components
static unsigned int GetItemCount();
static const char* GetItemText(unsigned int index, int column);
static void Select(unsigned int index);
static void UIScript_LoadMods(UIScript::Token);
static void UIScript_RunMod(UIScript::Token);
static void UIScript_ClearMods(UIScript::Token);
static void UIScript_LoadMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void UIScript_RunMod([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void UIScript_ClearMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
};
}

View File

@ -43,7 +43,7 @@ namespace Components
Dvar::Register<int>("cl_updateoldversion", REVISION, REVISION, REVISION, Game::DVAR_INIT, "Current version number.");
UIScript::Add("checkFirstLaunch", [](UIScript::Token)
UIScript::Add("checkFirstLaunch", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Dvar::Var("g_firstLaunch").get<bool>())
{
@ -52,7 +52,7 @@ namespace Components
}
});
UIScript::Add("visitWebsite", [](UIScript::Token)
UIScript::Add("visitWebsite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Utils::OpenUrl(Utils::Cache::GetStaticUrl(""));
});

View File

@ -553,7 +553,7 @@ namespace Components
// Fix mouse pitch adjustments
Dvar::Register<bool>("ui_mousePitch", false, Game::DVAR_ARCHIVE, "");
UIScript::Add("updateui_mousePitch", [](UIScript::Token)
UIScript::Add("updateui_mousePitch", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Dvar::Var("ui_mousePitch").get<bool>())
{

View File

@ -39,36 +39,36 @@ namespace Components
ServerInfo::PlayerContainer.currentPlayer = index;
}
void ServerInfo::ServerStatus(UIScript::Token)
void ServerInfo::ServerStatus([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerInfo::PlayerContainer.currentPlayer = 0;
ServerInfo::PlayerContainer.playerList.clear();
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
auto* serverInfo = ServerList::GetCurrentServer();
if (info)
{
Dvar::Var("uiSi_ServerName").set(info->hostname);
Dvar::Var("uiSi_MaxClients").set(info->clients);
Dvar::Var("uiSi_Version").set(info->shortversion);
Dvar::Var("uiSi_SecurityLevel").set(info->securityLevel);
Dvar::Var("uiSi_isPrivate").set(info->password ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_Hardcore").set(info->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
Dvar::Var("uiSi_ServerName").set(serverInfo->hostname);
Dvar::Var("uiSi_MaxClients").set(serverInfo->clients);
Dvar::Var("uiSi_Version").set(serverInfo->shortversion);
Dvar::Var("uiSi_SecurityLevel").set(serverInfo->securityLevel);
Dvar::Var("uiSi_isPrivate").set(serverInfo->password ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_Hardcore").set(serverInfo->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
Dvar::Var("uiSi_KillCam").set("@MENU_NO");
Dvar::Var("uiSi_ffType").set("@MENU_DISABLED");
Dvar::Var("uiSi_MapName").set(info->mapname);
Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info->mapname.data()));
Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info->gametype.data()));
Dvar::Var("uiSi_MapName").set(serverInfo->mapname);
Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(serverInfo->mapname.data()));
Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(serverInfo->gametype.data()));
Dvar::Var("uiSi_ModName").set("");
Dvar::Var("uiSi_aimAssist").set(info->aimassist ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_voiceChat").set(info->voice ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_aimAssist").set(serverInfo->aimassist ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_voiceChat").set(serverInfo->voice ? "@MENU_YES" : "@MENU_NO");
if (info->mod.size() > 5)
if (serverInfo->mod.size() > 5)
{
Dvar::Var("uiSi_ModName").set(info->mod.data() + 5);
Dvar::Var("uiSi_ModName").set(serverInfo->mod.data() + 5);
}
ServerInfo::PlayerContainer.target = info->addr;
ServerInfo::PlayerContainer.target = serverInfo->addr;
Network::SendCommand(ServerInfo::PlayerContainer.target, "getstatus");
}
}

View File

@ -33,7 +33,7 @@ namespace Components
static Container PlayerContainer;
static void ServerStatus(UIScript::Token);
static void ServerStatus([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static unsigned int GetPlayerCount();
static const char* GetPlayerText(unsigned int index, int column);

View File

@ -181,7 +181,7 @@ namespace Components
}
}
void ServerList::UpdateVisibleList(UIScript::Token)
void ServerList::UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
auto list = ServerList::GetList();
if (!list) return;
@ -190,7 +190,7 @@ namespace Components
if (tempList.empty())
{
ServerList::Refresh(UIScript::Token());
ServerList::Refresh(UIScript::Token(), info);
}
else
{
@ -208,12 +208,12 @@ namespace Components
}
}
void ServerList::RefreshVisibleList(UIScript::Token)
void ServerList::RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerList::RefreshVisibleListInternal(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token(), info);
}
void ServerList::RefreshVisibleListInternal(UIScript::Token, bool refresh)
void ServerList::RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh)
{
Dvar::Var("ui_serverSelected").set(false);
@ -224,38 +224,38 @@ namespace Components
if (refresh)
{
ServerList::Refresh(UIScript::Token());
ServerList::Refresh(UIScript::Token(), info);
return;
}
bool ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>();
bool ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>();
int ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>();
int ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>();
int ui_browserMod = Dvar::Var("ui_browserMod").get<int>();
int ui_joinGametype = Dvar::Var("ui_joinGametype").get<int>();
auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>();
auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>();
auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>();
auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>();
auto ui_browserMod = Dvar::Var("ui_browserMod").get<int>();
auto ui_joinGametype = Dvar::Var("ui_joinGametype").get<int>();
for (unsigned int i = 0; i < list->size(); ++i)
{
ServerList::ServerInfo* info = &(*list)[i];
auto* serverInfo = &(*list)[i];
// Filter full servers
if (!ui_browserShowFull && info->clients >= info->maxClients) continue;
if (!ui_browserShowFull && serverInfo->clients >= serverInfo->maxClients) continue;
// Filter empty servers
if (!ui_browserShowEmpty && info->clients <= 0) continue;
if (!ui_browserShowEmpty && serverInfo->clients <= 0) continue;
// Filter hardcore servers
if ((ui_browserShowHardcore == 0 && info->hardcore) || (ui_browserShowHardcore == 1 && !info->hardcore)) continue;
if ((ui_browserShowHardcore == 0 && serverInfo->hardcore) || (ui_browserShowHardcore == 1 && !serverInfo->hardcore)) continue;
// Filter servers with password
if ((ui_browserShowPassword == 0 && info->password) || (ui_browserShowPassword == 1 && !info->password)) continue;
if ((ui_browserShowPassword == 0 && serverInfo->password) || (ui_browserShowPassword == 1 && !serverInfo->password)) continue;
// Don't show modded servers
if ((ui_browserMod == 0 && info->mod.size()) || (ui_browserMod == 1 && !info->mod.size())) continue;
if ((ui_browserMod == 0 && serverInfo->mod.size()) || (ui_browserMod == 1 && !serverInfo->mod.size())) continue;
// Filter by gametype
if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != info->gametype) continue;
if (ui_joinGametype > 0 && (ui_joinGametype - 1) < *Game::gameTypeCount && Game::gameTypes[(ui_joinGametype - 1)].gameType != serverInfo->gametype) continue;
ServerList::VisibleList.push_back(i);
}
@ -263,7 +263,7 @@ namespace Components
ServerList::SortList();
}
void ServerList::Refresh(UIScript::Token)
void ServerList::Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Dvar::Var("ui_serverSelected").set(false);
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
@ -388,7 +388,7 @@ namespace Components
auto list = ServerList::GetList();
if (list) list->clear();
ServerList::RefreshVisibleListInternal(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
Game::ShowMessageBox("Server removed from favourites.", "Success");
}
@ -556,7 +556,7 @@ namespace Components
if (lList)
{
lList->push_back(server);
ServerList::RefreshVisibleListInternal(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
}
}
}
@ -717,7 +717,7 @@ namespace Components
netSource.set(source);
ServerList::RefreshVisibleListInternal(UIScript::Token(), true);
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr, true);
}
void ServerList::UpdateGameType()
@ -733,7 +733,7 @@ namespace Components
joinGametype.set(gametype);
ServerList::RefreshVisibleListInternal(UIScript::Token());
ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
}
void ServerList::UpdateVisibleInfo()
@ -853,20 +853,18 @@ namespace Components
UIScript::Add("RefreshServers", ServerList::Refresh);
UIScript::Add("JoinServer", [](UIScript::Token)
UIScript::Add("JoinServer", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerList::ServerInfo* info = ServerList::GetServer(ServerList::CurrentServer);
if (info)
auto* serverInfo = ServerList::GetServer(ServerList::CurrentServer);
if (serverInfo)
{
Party::Connect(info->addr);
Party::Connect(serverInfo->addr);
}
});
UIScript::Add("ServerSort", [](UIScript::Token token)
UIScript::Add("ServerSort", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
int key = token.get<int>();
auto key = token.get<int>();
if (ServerList::SortKey == key)
{
ServerList::SortAsc = !ServerList::SortAsc;
@ -881,22 +879,21 @@ namespace Components
ServerList::SortList();
});
UIScript::Add("CreateListFavorite", [](UIScript::Token)
UIScript::Add("CreateListFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
auto* serverInfo = ServerList::GetCurrentServer();
if (info)
{
ServerList::StoreFavourite(info->addr.getString());
ServerList::StoreFavourite(serverInfo->addr.getString());
}
});
UIScript::Add("CreateFavorite", [](UIScript::Token)
UIScript::Add("CreateFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerList::StoreFavourite(Dvar::Var("ui_favoriteAddress").get<std::string>());
});
UIScript::Add("CreateCurrentServerFavorite", [](UIScript::Token)
UIScript::Add("CreateCurrentServerFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Game::CL_IsCgameInitialized())
{
@ -908,14 +905,13 @@ namespace Components
}
});
UIScript::Add("DeleteFavorite", [](UIScript::Token)
UIScript::Add("DeleteFavorite", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
ServerList::ServerInfo* info = ServerList::GetCurrentServer();
if (info)
auto* serverInfo = ServerList::GetCurrentServer();
if (serverInfo)
{
ServerList::RemoveFavourite(info->addr.getString());
};
ServerList::RemoveFavourite(serverInfo->addr.getString());
}
});
#ifdef _DEBUG

View File

@ -35,10 +35,10 @@ namespace Components
ServerList();
~ServerList();
static void Refresh(UIScript::Token);
static void RefreshVisibleList(UIScript::Token);
static void RefreshVisibleListInternal(UIScript::Token, bool refresh = false);
static void UpdateVisibleList(UIScript::Token);
static void Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh = false);
static void UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void InsertRequest(Network::Address address);
static void Insert(const Network::Address& address, const Utils::InfoString& info);

View File

@ -14,7 +14,7 @@ namespace Components
Dvar::Register<const char*>("ui_startupNextButtonText", "", Game::DVAR_EXTERNAL | Game::DVAR_INIT, "");
}, Scheduler::Pipeline::MAIN);
UIScript::Add("nextStartupMessage", [](UIScript::Token)
UIScript::Add("nextStartupMessage", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (!StartupMessages::MessageList.size()) return;

View File

@ -56,7 +56,7 @@ namespace Components
}
}
void Stats::UpdateClasses(UIScript::Token)
void Stats::UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Stats::SendStats();
}

View File

@ -10,7 +10,7 @@ namespace Components
static bool IsMaxLevel();
private:
static void UpdateClasses(UIScript::Token token);
static void UpdateClasses([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void SendStats();
static int SaveStats(char* dest, const char* folder, const char* buffer, size_t length);

View File

@ -181,7 +181,7 @@ namespace Components
meta.write(nlohmann::json(Theatre::CurrentInfo.to_json()).dump());
}
void Theatre::LoadDemos(UIScript::Token)
void Theatre::LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Theatre::CurrentSelection = 0;
Theatre::Demos.clear();
@ -199,17 +199,16 @@ namespace Components
if (metaObject.is_object())
{
Theatre::DemoInfo info;
info.name = demo.substr(0, demo.find_last_of("."));
info.author = metaObject["author"].get<std::string>();
info.gametype = metaObject["gametype"].get<std::string>();
info.mapname = metaObject["mapname"].get<std::string>();
info.length = metaObject["length"].get<int>();
Theatre::DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
demoInfo.author = metaObject["author"].get<std::string>();
demoInfo.gametype = metaObject["gametype"].get<std::string>();
demoInfo.mapname = metaObject["mapname"].get<std::string>();
demoInfo.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>();
info.timeStamp = _atoi64(timestamp.data());
demoInfo.timeStamp = _atoi64(timestamp.data());
Theatre::Demos.push_back(info);
Theatre::Demos.push_back(demoInfo);
}
}
}
@ -218,16 +217,16 @@ namespace Components
std::reverse(Theatre::Demos.begin(), Theatre::Demos.end());
}
void Theatre::DeleteDemo(UIScript::Token)
void Theatre::DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Theatre::CurrentSelection < Theatre::Demos.size())
{
Theatre::DemoInfo info = Theatre::Demos[Theatre::CurrentSelection];
Theatre::DemoInfo demoInfo = Theatre::Demos[Theatre::CurrentSelection];
Logger::Print("Deleting demo {}...\n", info.name);
Logger::Print("Deleting demo {}...\n", demoInfo.name);
FileSystem::_DeleteFile("demos", info.name + ".dm_13");
FileSystem::_DeleteFile("demos", info.name + ".dm_13.json");
FileSystem::_DeleteFile("demos", demoInfo.name + ".dm_13");
FileSystem::_DeleteFile("demos", demoInfo.name + ".dm_13.json");
// Reset our ui_demo_* dvars here, because the theater menu needs it.
Dvar::Var("ui_demo_mapname").set("");
@ -238,11 +237,11 @@ namespace Components
Dvar::Var("ui_demo_date").set("");
// Reload demos
Theatre::LoadDemos(UIScript::Token());
Theatre::LoadDemos(UIScript::Token(), info);
}
}
void Theatre::PlayDemo(UIScript::Token)
void Theatre::PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (Theatre::CurrentSelection < Theatre::Demos.size())
{

View File

@ -44,9 +44,9 @@ namespace Components
static void WriteBaseline();
static void StoreBaseline(PBYTE snapshotMsg);
static void LoadDemos(UIScript::Token);
static void DeleteDemo(UIScript::Token);
static void PlayDemo(UIScript::Token);
static void LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static unsigned int GetDemoCount();
static const char* GetDemoText(unsigned int item, int column);

View File

@ -311,7 +311,7 @@ namespace Components
}
}
void UIFeeder::ApplyMap(UIScript::Token)
void UIFeeder::ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
const auto mapname = Dvar::Var("ui_map_name").get<std::string>();
@ -319,7 +319,7 @@ namespace Components
Utils::Hook::Call<void(const char*)>(0x503B50)(mapname.data()); // Party_SetDisplayMapName
}
void UIFeeder::ApplyInitialMap(UIScript::Token)
void UIFeeder::ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
const auto mapname = Dvar::Var("ui_mapname").get<std::string>();

View File

@ -56,7 +56,7 @@ namespace Components
static unsigned int GetMapCount();
static const char* GetMapText(unsigned int index, int column);
static void SelectMap(unsigned int index);
static void ApplyMap(UIScript::Token token);
static void ApplyInitialMap(UIScript::Token token);
static void ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void ApplyInitialMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
};
}

View File

@ -5,17 +5,17 @@ namespace Components
std::unordered_map<std::string, Utils::Slot<UIScript::Callback>> UIScript::UIScripts;
std::unordered_map<int, Utils::Slot<UIScript::CallbackRaw>> UIScript::UIOwnerDraws;
template<> int UIScript::Token::get()
template<> int UIScript::Token::get() const
{
if (this->isValid())
{
return atoi(this->token);
return std::atoi(this->token);
}
return 0;
}
template<> const char* UIScript::Token::get()
template<> const char* UIScript::Token::get() const
{
if (this->isValid())
{
@ -25,12 +25,12 @@ namespace Components
return "";
}
template<> std::string UIScript::Token::get()
template<> std::string UIScript::Token::get() const
{
return this->get<const char*>();
return {this->get<const char*>()};
}
bool UIScript::Token::isValid()
bool UIScript::Token::isValid() const
{
return (this->token && this->token[0]);
}
@ -43,12 +43,18 @@ namespace Components
}
}
void UIScript::Add(const std::string& name, Utils::Slot<UIScript::Callback> callback)
Game::uiInfo_s* UIScript::UI_GetClientInfo(int localClientNum)
{
AssertIn(localClientNum, Game::STATIC_MAX_LOCAL_CLIENTS);
return &Game::uiInfoArray[localClientNum];
}
void UIScript::Add(const std::string& name, const Utils::Slot<UIScript::Callback>& callback)
{
UIScript::UIScripts[name] = callback;
}
void UIScript::AddOwnerDraw(int ownerdraw, Utils::Slot<UIScript::CallbackRaw> callback)
void UIScript::AddOwnerDraw(int ownerdraw, const Utils::Slot<UIScript::CallbackRaw>& callback)
{
UIScript::UIOwnerDraws[ownerdraw] = callback;
}
@ -57,7 +63,8 @@ namespace Components
{
if (UIScript::UIScripts.contains(name))
{
UIScript::UIScripts[name](UIScript::Token(args));
const auto* info = UIScript::UI_GetClientInfo(0);
UIScript::UIScripts[name](UIScript::Token(args), info);
return true;
}
@ -111,6 +118,8 @@ namespace Components
UIScript::UIScript()
{
AssertSize(Game::uiInfo_s, 0x22FC);
if (Dedicated::IsEnabled()) return;
// Install handler

View File

@ -11,12 +11,12 @@ namespace Components
class Token
{
public:
Token() : token(nullptr) {};
Token(const char** args) : token(nullptr) { this->parse(args); };
Token(const Token &obj) { this->token = obj.token; };
Token() : token(nullptr) {}
Token(const char** args) : token(nullptr) { this->parse(args); }
Token(const Token &obj) { this->token = obj.token; }
template<typename T> T get();
bool isValid();
template<typename T> T get() const;
bool isValid() const;
private:
char* token;
@ -24,11 +24,13 @@ namespace Components
void parse(const char** args);
};
typedef void(Callback)(Token token);
typedef void(Callback)(const Token& token, const Game::uiInfo_s* info);
typedef void(CallbackRaw)();
static void Add(const std::string& name, Utils::Slot<Callback> callback);
static void AddOwnerDraw(int ownerdraw, Utils::Slot<CallbackRaw> callback);
static Game::uiInfo_s* UI_GetClientInfo(int localClientNum);
static void Add(const std::string& name, const Utils::Slot<Callback>& callback);
static void AddOwnerDraw(int ownerdraw, const Utils::Slot<CallbackRaw>& callback);
private:
static void OwnerDrawHandleKeyStub(int ownerDraw, int flags, float *special, int key);

View File

@ -62,6 +62,12 @@ namespace Components
strncpy_s(arg2, params->get(2), _TRUNCATE);
strncpy_s(arg3, params->get(3), _TRUNCATE);
if (!MapRotation::Contains("gametype", arg2) ||
!MapRotation::Contains("map", arg3))
{
return false;
}
if (!Game::Scr_IsValidGameType(arg2))
{
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65));
@ -116,6 +122,11 @@ namespace Components
bool Vote::HandleMap([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
{
if (!MapRotation::Contains("map", params->get(2)))
{
return false;
}
sprintf_s(Game::level->voteString, "%s %s", params->get(1), params->get(2));
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", params->get(2));
return true;
@ -123,6 +134,11 @@ namespace Components
bool Vote::HandleGametype([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params)
{
if (!MapRotation::Contains("gametype", params->get(2)))
{
return false;
}
if (!Game::Scr_IsValidGameType(params->get(2)))
{
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65));
@ -272,5 +288,41 @@ namespace Components
{
ClientCommand::Add("callvote", Cmd_CallVote_f);
ClientCommand::Add("vote", Cmd_Vote_f);
UIScript::Add("voteKick", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (info->playerIndex >= 0 && info->playerIndex < Game::sharedUiInfo->playerCount)
{
Game::Cbuf_AddText(0, VA("callvote kick \"%s\"\n", Game::sharedUiInfo->playerNames[info->playerIndex]));
}
});
UIScript::Add("voteTempBan", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if (info->playerIndex >= 0 && info->playerIndex < Game::sharedUiInfo->playerCount)
{
Game::Cbuf_AddText(0, VA("callvote tempBanUser \"%s\"\n", Game::sharedUiInfo->playerNames[info->playerIndex]));
}
});
UIScript::Add("voteTypeMap", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Game::Cbuf_AddText(0, VA("callvote typemap %s %s\n", Game::sharedUiInfo->gameTypes[(*Game::ui_netGameType)->current.integer].gameType,
Game::sharedUiInfo->mapList[(*Game::ui_netGameType)->current.integer].mapName));
});
UIScript::Add("voteMap", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
if ((*Game::ui_currentMap)->current.integer >= 0 &&
(*Game::ui_currentMap)->current.integer <Game::sharedUiInfo->mapCount)
{
Game::Cbuf_AddText(0, VA("callvote map %s\n", Game::sharedUiInfo->mapList[(*Game::ui_currentMap)->current.integer].mapName));
}
});
UIScript::Add("voteGame", []([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info)
{
Game::Cbuf_AddText(0, VA("callvote g_gametype %s\n", Game::sharedUiInfo->gameTypes[(*Game::ui_netGameType)->current.integer].gameType));
});
}
}

View File

@ -11,7 +11,8 @@ namespace Components
using CommandHandler = std::function<bool(const Game::gentity_s* ent, const Command::ServerParams* params)>;
static std::unordered_map<std::string, CommandHandler> VoteCommands;
static constexpr auto* CallVoteDesc = "%c \"GAME_VOTECOMMANDSARE\x15 map_restart, map_rotate, map <mapname>, g_gametype <typename>, typemap <typename> <mapname>\"";
static constexpr auto* CallVoteDesc = "%c \"GAME_VOTECOMMANDSARE\x15 map_restart, map_rotate, map <mapname>, g_gametype <typename>, typemap <typename> <mapname>, "
" kick <player>, tempBanUser <player>\"";
static void DisplayVote(const Game::gentity_s* ent);
static bool IsInvalidVoteString(const std::string& input);

View File

@ -53,6 +53,11 @@ namespace Game
const dvar_t** version = reinterpret_cast<const dvar_t**>(0x1AD7930);
const dvar_t** ui_currentMap = reinterpret_cast<const dvar_t**>(0x62E2834);
const dvar_t** ui_gametype = reinterpret_cast<const dvar_t**>(0x62E2828);
const dvar_t** ui_mapname = reinterpret_cast<const dvar_t**>(0x62E279C);
const dvar_t** ui_netGameType = reinterpret_cast<const dvar_t**>(0x62E2838);
__declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource)
{
static DWORD Dvar_SetVariant_t = 0x647400;

View File

@ -109,6 +109,11 @@ namespace Game
extern const dvar_t** version;
extern const dvar_t** ui_currentMap;
extern const dvar_t** ui_gametype;
extern const dvar_t** ui_mapname;
extern const dvar_t** ui_netGameType;
extern void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source);
extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source);
}

View File

@ -408,6 +408,8 @@ namespace Game
unsigned int* playerCardUIStringIndex = reinterpret_cast<unsigned int*>(0x62CD7A8);
char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38] = reinterpret_cast<char(*)[PLAYER_CARD_UI_STRING_COUNT][38]>(0x62CB4F8);
uiInfo_s* uiInfoArray = reinterpret_cast<uiInfo_s*>(0x62E2858);
int* logfile = reinterpret_cast<int*>(0x1AD8F28);
GamerSettingState* gamerSettings = reinterpret_cast<GamerSettingState*>(0x107D3E8);

View File

@ -758,6 +758,8 @@ namespace Game
extern unsigned int* playerCardUIStringIndex;
extern char (*playerCardUIStringBuf)[PLAYER_CARD_UI_STRING_COUNT][38];
extern uiInfo_s* uiInfoArray;
extern int* logfile;
extern GamerSettingState* gamerSettings;

View File

@ -8900,6 +8900,27 @@ namespace Game
int dataSize;
};
struct uiInfo_s
{
UiContext uiDC;
int myTeamCount;
int playerRefresh;
int playerIndex;
int timeIndex;
int previousTimes[4];
uiMenuCommand_t currentMenuType;
bool allowScriptMenuResponse;
char findPlayerName[1024];
char foundPlayerServerAddresses[16][64];
char foundPlayerServerNames[16][64];
int numFoundPlayerServers;
int nextFindPlayerRefresh;
unsigned int mailUpdateTime;
char mailIndices[64];
int mailCount;
int selectedMail;
};
#pragma endregion
#ifndef IDA