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; Auth::TokenContainer.cancel = true;
Logger::Print("Token incrementation process canceled!\n"); 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, ""); Dvar::Register<const char*>("ui_dl_transRate", "", Game::DVAR_NONE, "");
}, Scheduler::Pipeline::MAIN); }, 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(); Download::CLDownload.clear();
}); });

View File

@ -604,12 +604,12 @@ namespace Components
// Show blue icons on the minimap // Show blue icons on the minimap
Utils::Hook(0x493130, Friends::IsClientInParty, HOOK_JUMP).install()->quick(); 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(); 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); std::lock_guard<std::recursive_mutex> _(Friends::Mutex);
if (Friends::CurrentFriend >= Friends::FriendsList.size()) return; 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 nlohmann::json MapRotation::RotationData::to_json() const
{ {
std::vector<std::string> mapVector; std::vector<std::string> mapVector;
@ -109,6 +118,17 @@ namespace Components
Logger::Debug("DedicatedRotation size after parsing is '{}'", DedicatedRotation.getEntriesSize()); 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() void MapRotation::AddMapRotationCommands()
{ {
Command::Add("addMap", [](Command::Params* params) 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() bool MapRotation::ShouldRotate()
{ {
if (!Dedicated::IsEnabled() && SVDontRotate.get<bool>()) if (!Dedicated::IsEnabled() && SVDontRotate.get<bool>())
@ -276,14 +301,7 @@ namespace Components
return; return;
} }
const std::string mapRotation = (*Game::sv_mapRotation)->current.string; LoadMapRotation();
// 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);
}
if (DedicatedRotation.getEntriesSize() == 0) if (DedicatedRotation.getEntriesSize() == 0)
{ {
Logger::Print(Game::CON_CHANNEL_SERVER, "{} is empty or contains invalid data. Restarting map\n", (*Game::sv_mapRotation)->name); 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: public:
MapRotation(); MapRotation();
static bool Contains(const std::string& key, const std::string& value);
bool unitTest() override; bool unitTest() override;
private: private:
@ -33,7 +35,8 @@ namespace Components
void parse(const std::string& data); 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; [[nodiscard]] nlohmann::json to_json() const;
private: private:
@ -50,6 +53,7 @@ namespace Components
static RotationData DedicatedRotation; static RotationData DedicatedRotation;
static void LoadRotation(const std::string& data); static void LoadRotation(const std::string& data);
static void LoadMapRotation();
// Use these commands before SV_MapRotate_f is called // Use these commands before SV_MapRotate_f is called
static void AddMapRotationCommands(); static void AddMapRotationCommands();

View File

@ -768,7 +768,7 @@ namespace Components
Maps::UpdateDlcStatus(); 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>(); int dlc = token.get<int>();

View File

@ -794,7 +794,7 @@ namespace Components
// don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail) // don't load ASSET_TYPE_MENU assets for every menu (might cause patch menus to fail)
Utils::Hook::Nop(0x453406, 5); Utils::Hook::Nop(0x453406, 5);
//make Com_Error and similar go back to main_text instead of menu_xboxlive. // make Com_Error and similar go back to main_text instead of menu_xboxlive.
Utils::Hook::SetString(0x6FC790, "main_text"); Utils::Hook::SetString(0x6FC790, "main_text");
Command::Add("openmenu", [](Command::Params* params) Command::Add("openmenu", [](Command::Params* params)

View File

@ -40,7 +40,7 @@ namespace Components
ModList::CurrentMod = index; 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"; auto folder = Dvar::Var("fs_basepath").get<std::string>() + "\\mods";
Logger::Debug("Searching for mods in {}...", folder); Logger::Debug("Searching for mods in {}...", folder);
@ -48,7 +48,7 @@ namespace Components
Logger::Debug("Found {} mods!", ModList::Mods.size()); 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()) 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"); auto fsGame = Dvar::Var("fs_game");
fsGame.set(""); fsGame.set("");

View File

@ -18,8 +18,8 @@ namespace Components
static unsigned int GetItemCount(); static unsigned int GetItemCount();
static const char* GetItemText(unsigned int index, int column); static const char* GetItemText(unsigned int index, int column);
static void Select(unsigned int index); static void Select(unsigned int index);
static void UIScript_LoadMods(UIScript::Token); static void UIScript_LoadMods([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void UIScript_RunMod(UIScript::Token); static void UIScript_RunMod([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void UIScript_ClearMods(UIScript::Token); 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."); 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>()) 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("")); Utils::OpenUrl(Utils::Cache::GetStaticUrl(""));
}); });

View File

@ -553,7 +553,7 @@ namespace Components
// Fix mouse pitch adjustments // Fix mouse pitch adjustments
Dvar::Register<bool>("ui_mousePitch", false, Game::DVAR_ARCHIVE, ""); 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>()) if (Dvar::Var("ui_mousePitch").get<bool>())
{ {

View File

@ -39,36 +39,36 @@ namespace Components
ServerInfo::PlayerContainer.currentPlayer = index; 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.currentPlayer = 0;
ServerInfo::PlayerContainer.playerList.clear(); ServerInfo::PlayerContainer.playerList.clear();
ServerList::ServerInfo* info = ServerList::GetCurrentServer(); auto* serverInfo = ServerList::GetCurrentServer();
if (info) if (info)
{ {
Dvar::Var("uiSi_ServerName").set(info->hostname); Dvar::Var("uiSi_ServerName").set(serverInfo->hostname);
Dvar::Var("uiSi_MaxClients").set(info->clients); Dvar::Var("uiSi_MaxClients").set(serverInfo->clients);
Dvar::Var("uiSi_Version").set(info->shortversion); Dvar::Var("uiSi_Version").set(serverInfo->shortversion);
Dvar::Var("uiSi_SecurityLevel").set(info->securityLevel); Dvar::Var("uiSi_SecurityLevel").set(serverInfo->securityLevel);
Dvar::Var("uiSi_isPrivate").set(info->password ? "@MENU_YES" : "@MENU_NO"); Dvar::Var("uiSi_isPrivate").set(serverInfo->password ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_Hardcore").set(info->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED"); Dvar::Var("uiSi_Hardcore").set(serverInfo->hardcore ? "@MENU_ENABLED" : "@MENU_DISABLED");
Dvar::Var("uiSi_KillCam").set("@MENU_NO"); Dvar::Var("uiSi_KillCam").set("@MENU_NO");
Dvar::Var("uiSi_ffType").set("@MENU_DISABLED"); Dvar::Var("uiSi_ffType").set("@MENU_DISABLED");
Dvar::Var("uiSi_MapName").set(info->mapname); Dvar::Var("uiSi_MapName").set(serverInfo->mapname);
Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(info->mapname.data())); Dvar::Var("uiSi_MapNameLoc").set(Game::UI_LocalizeMapName(serverInfo->mapname.data()));
Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(info->gametype.data())); Dvar::Var("uiSi_GameType").set(Game::UI_LocalizeGameType(serverInfo->gametype.data()));
Dvar::Var("uiSi_ModName").set(""); Dvar::Var("uiSi_ModName").set("");
Dvar::Var("uiSi_aimAssist").set(info->aimassist ? "@MENU_YES" : "@MENU_NO"); Dvar::Var("uiSi_aimAssist").set(serverInfo->aimassist ? "@MENU_YES" : "@MENU_NO");
Dvar::Var("uiSi_voiceChat").set(info->voice ? "@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"); Network::SendCommand(ServerInfo::PlayerContainer.target, "getstatus");
} }
} }

View File

@ -33,7 +33,7 @@ namespace Components
static Container PlayerContainer; 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 unsigned int GetPlayerCount();
static const char* GetPlayerText(unsigned int index, int column); 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(); auto list = ServerList::GetList();
if (!list) return; if (!list) return;
@ -190,7 +190,7 @@ namespace Components
if (tempList.empty()) if (tempList.empty())
{ {
ServerList::Refresh(UIScript::Token()); ServerList::Refresh(UIScript::Token(), info);
} }
else 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); Dvar::Var("ui_serverSelected").set(false);
@ -224,38 +224,38 @@ namespace Components
if (refresh) if (refresh)
{ {
ServerList::Refresh(UIScript::Token()); ServerList::Refresh(UIScript::Token(), info);
return; return;
} }
bool ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>(); auto ui_browserShowFull = Dvar::Var("ui_browserShowFull").get<bool>();
bool ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>(); auto ui_browserShowEmpty = Dvar::Var("ui_browserShowEmpty").get<bool>();
int ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>(); auto ui_browserShowHardcore = Dvar::Var("ui_browserKillcam").get<int>();
int ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>(); auto ui_browserShowPassword = Dvar::Var("ui_browserShowPassword").get<int>();
int ui_browserMod = Dvar::Var("ui_browserMod").get<int>(); auto ui_browserMod = Dvar::Var("ui_browserMod").get<int>();
int ui_joinGametype = Dvar::Var("ui_joinGametype").get<int>(); auto ui_joinGametype = Dvar::Var("ui_joinGametype").get<int>();
for (unsigned int i = 0; i < list->size(); ++i) for (unsigned int i = 0; i < list->size(); ++i)
{ {
ServerList::ServerInfo* info = &(*list)[i]; auto* serverInfo = &(*list)[i];
// Filter full servers // Filter full servers
if (!ui_browserShowFull && info->clients >= info->maxClients) continue; if (!ui_browserShowFull && serverInfo->clients >= serverInfo->maxClients) continue;
// Filter empty servers // Filter empty servers
if (!ui_browserShowEmpty && info->clients <= 0) continue; if (!ui_browserShowEmpty && serverInfo->clients <= 0) continue;
// Filter hardcore servers // 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 // 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 // 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 // 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); ServerList::VisibleList.push_back(i);
} }
@ -263,7 +263,7 @@ namespace Components
ServerList::SortList(); 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); Dvar::Var("ui_serverSelected").set(false);
//Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0"); //Localization::Set("MPUI_SERVERQUERIED", "Sent requests: 0/0");
@ -388,7 +388,7 @@ namespace Components
auto list = ServerList::GetList(); auto list = ServerList::GetList();
if (list) list->clear(); if (list) list->clear();
ServerList::RefreshVisibleListInternal(UIScript::Token()); ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
Game::ShowMessageBox("Server removed from favourites.", "Success"); Game::ShowMessageBox("Server removed from favourites.", "Success");
} }
@ -556,7 +556,7 @@ namespace Components
if (lList) if (lList)
{ {
lList->push_back(server); lList->push_back(server);
ServerList::RefreshVisibleListInternal(UIScript::Token()); ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
} }
} }
} }
@ -717,7 +717,7 @@ namespace Components
netSource.set(source); netSource.set(source);
ServerList::RefreshVisibleListInternal(UIScript::Token(), true); ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr, true);
} }
void ServerList::UpdateGameType() void ServerList::UpdateGameType()
@ -733,7 +733,7 @@ namespace Components
joinGametype.set(gametype); joinGametype.set(gametype);
ServerList::RefreshVisibleListInternal(UIScript::Token()); ServerList::RefreshVisibleListInternal(UIScript::Token(), nullptr);
} }
void ServerList::UpdateVisibleInfo() void ServerList::UpdateVisibleInfo()
@ -853,20 +853,18 @@ namespace Components
UIScript::Add("RefreshServers", ServerList::Refresh); 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); auto* serverInfo = ServerList::GetServer(ServerList::CurrentServer);
if (serverInfo)
if (info)
{ {
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) if (ServerList::SortKey == key)
{ {
ServerList::SortAsc = !ServerList::SortAsc; ServerList::SortAsc = !ServerList::SortAsc;
@ -881,22 +879,21 @@ namespace Components
ServerList::SortList(); 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) 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>()); 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()) 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(); auto* serverInfo = ServerList::GetCurrentServer();
if (serverInfo)
if (info)
{ {
ServerList::RemoveFavourite(info->addr.getString()); ServerList::RemoveFavourite(serverInfo->addr.getString());
}; }
}); });
#ifdef _DEBUG #ifdef _DEBUG

View File

@ -35,10 +35,10 @@ namespace Components
ServerList(); ServerList();
~ServerList(); ~ServerList();
static void Refresh(UIScript::Token); static void Refresh([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void RefreshVisibleList(UIScript::Token); static void RefreshVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void RefreshVisibleListInternal(UIScript::Token, bool refresh = false); static void RefreshVisibleListInternal([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info, bool refresh = false);
static void UpdateVisibleList(UIScript::Token); static void UpdateVisibleList([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void InsertRequest(Network::Address address); static void InsertRequest(Network::Address address);
static void Insert(const Network::Address& address, const Utils::InfoString& info); 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, ""); Dvar::Register<const char*>("ui_startupNextButtonText", "", Game::DVAR_EXTERNAL | Game::DVAR_INIT, "");
}, Scheduler::Pipeline::MAIN); }, 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; 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(); Stats::SendStats();
} }

View File

@ -10,7 +10,7 @@ namespace Components
static bool IsMaxLevel(); static bool IsMaxLevel();
private: 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 void SendStats();
static int SaveStats(char* dest, const char* folder, const char* buffer, size_t length); 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()); 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::CurrentSelection = 0;
Theatre::Demos.clear(); Theatre::Demos.clear();
@ -199,17 +199,16 @@ namespace Components
if (metaObject.is_object()) if (metaObject.is_object())
{ {
Theatre::DemoInfo info; Theatre::DemoInfo demoInfo;
demoInfo.name = demo.substr(0, demo.find_last_of("."));
info.name = demo.substr(0, demo.find_last_of(".")); demoInfo.author = metaObject["author"].get<std::string>();
info.author = metaObject["author"].get<std::string>(); demoInfo.gametype = metaObject["gametype"].get<std::string>();
info.gametype = metaObject["gametype"].get<std::string>(); demoInfo.mapname = metaObject["mapname"].get<std::string>();
info.mapname = metaObject["mapname"].get<std::string>(); demoInfo.length = metaObject["length"].get<int>();
info.length = metaObject["length"].get<int>();
auto timestamp = metaObject["timestamp"].get<std::string>(); 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()); 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()) 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", demoInfo.name + ".dm_13");
FileSystem::_DeleteFile("demos", info.name + ".dm_13.json"); FileSystem::_DeleteFile("demos", demoInfo.name + ".dm_13.json");
// Reset our ui_demo_* dvars here, because the theater menu needs it. // Reset our ui_demo_* dvars here, because the theater menu needs it.
Dvar::Var("ui_demo_mapname").set(""); Dvar::Var("ui_demo_mapname").set("");
@ -238,11 +237,11 @@ namespace Components
Dvar::Var("ui_demo_date").set(""); Dvar::Var("ui_demo_date").set("");
// Reload demos // 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()) if (Theatre::CurrentSelection < Theatre::Demos.size())
{ {

View File

@ -44,9 +44,9 @@ namespace Components
static void WriteBaseline(); static void WriteBaseline();
static void StoreBaseline(PBYTE snapshotMsg); static void StoreBaseline(PBYTE snapshotMsg);
static void LoadDemos(UIScript::Token); static void LoadDemos([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void DeleteDemo(UIScript::Token); static void DeleteDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void PlayDemo(UIScript::Token); static void PlayDemo([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static unsigned int GetDemoCount(); static unsigned int GetDemoCount();
static const char* GetDemoText(unsigned int item, int column); 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>(); 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 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>(); const auto mapname = Dvar::Var("ui_mapname").get<std::string>();

View File

@ -56,7 +56,7 @@ namespace Components
static unsigned int GetMapCount(); static unsigned int GetMapCount();
static const char* GetMapText(unsigned int index, int column); static const char* GetMapText(unsigned int index, int column);
static void SelectMap(unsigned int index); static void SelectMap(unsigned int index);
static void ApplyMap(UIScript::Token token); static void ApplyMap([[maybe_unused]] const UIScript::Token& token, [[maybe_unused]] const Game::uiInfo_s* info);
static void ApplyInitialMap(UIScript::Token token); 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<std::string, Utils::Slot<UIScript::Callback>> UIScript::UIScripts;
std::unordered_map<int, Utils::Slot<UIScript::CallbackRaw>> UIScript::UIOwnerDraws; std::unordered_map<int, Utils::Slot<UIScript::CallbackRaw>> UIScript::UIOwnerDraws;
template<> int UIScript::Token::get() template<> int UIScript::Token::get() const
{ {
if (this->isValid()) if (this->isValid())
{ {
return atoi(this->token); return std::atoi(this->token);
} }
return 0; return 0;
} }
template<> const char* UIScript::Token::get() template<> const char* UIScript::Token::get() const
{ {
if (this->isValid()) if (this->isValid())
{ {
@ -25,12 +25,12 @@ namespace Components
return ""; 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]); 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; 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; UIScript::UIOwnerDraws[ownerdraw] = callback;
} }
@ -57,7 +63,8 @@ namespace Components
{ {
if (UIScript::UIScripts.contains(name)) 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; return true;
} }
@ -111,6 +118,8 @@ namespace Components
UIScript::UIScript() UIScript::UIScript()
{ {
AssertSize(Game::uiInfo_s, 0x22FC);
if (Dedicated::IsEnabled()) return; if (Dedicated::IsEnabled()) return;
// Install handler // Install handler

View File

@ -11,12 +11,12 @@ namespace Components
class Token class Token
{ {
public: public:
Token() : token(nullptr) {}; Token() : token(nullptr) {}
Token(const char** args) : token(nullptr) { this->parse(args); }; Token(const char** args) : token(nullptr) { this->parse(args); }
Token(const Token &obj) { this->token = obj.token; }; Token(const Token &obj) { this->token = obj.token; }
template<typename T> T get(); template<typename T> T get() const;
bool isValid(); bool isValid() const;
private: private:
char* token; char* token;
@ -24,11 +24,13 @@ namespace Components
void parse(const char** args); void parse(const char** args);
}; };
typedef void(Callback)(Token token); typedef void(Callback)(const Token& token, const Game::uiInfo_s* info);
typedef void(CallbackRaw)(); typedef void(CallbackRaw)();
static void Add(const std::string& name, Utils::Slot<Callback> callback); static Game::uiInfo_s* UI_GetClientInfo(int localClientNum);
static void AddOwnerDraw(int ownerdraw, Utils::Slot<CallbackRaw> callback);
static void Add(const std::string& name, const Utils::Slot<Callback>& callback);
static void AddOwnerDraw(int ownerdraw, const Utils::Slot<CallbackRaw>& callback);
private: private:
static void OwnerDrawHandleKeyStub(int ownerDraw, int flags, float *special, int key); 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(arg2, params->get(2), _TRUNCATE);
strncpy_s(arg3, params->get(3), _TRUNCATE); strncpy_s(arg3, params->get(3), _TRUNCATE);
if (!MapRotation::Contains("gametype", arg2) ||
!MapRotation::Contains("map", arg3))
{
return false;
}
if (!Game::Scr_IsValidGameType(arg2)) if (!Game::Scr_IsValidGameType(arg2))
{ {
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65)); 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) 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->voteString, "%s %s", params->get(1), params->get(2));
sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", params->get(2)); sprintf_s(Game::level->voteDisplayString, "GAME_VOTE_MAP\x15%s", params->get(2));
return true; return true;
@ -123,6 +134,11 @@ namespace Components
bool Vote::HandleGametype([[maybe_unused]] const Game::gentity_s* ent, [[maybe_unused]] const Command::ServerParams* params) 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))) if (!Game::Scr_IsValidGameType(params->get(2)))
{ {
Game::SV_GameSendServerCommand(ent - Game::g_entities, Game::SV_CMD_CAN_IGNORE, VA("%c \"GAME_INVALIDGAMETYPE\"", 0x65)); 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("callvote", Cmd_CallVote_f);
ClientCommand::Add("vote", Cmd_Vote_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)>; using CommandHandler = std::function<bool(const Game::gentity_s* ent, const Command::ServerParams* params)>;
static std::unordered_map<std::string, CommandHandler> VoteCommands; 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 void DisplayVote(const Game::gentity_s* ent);
static bool IsInvalidVoteString(const std::string& input); 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** 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) __declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource)
{ {
static DWORD Dvar_SetVariant_t = 0x647400; static DWORD Dvar_SetVariant_t = 0x647400;

View File

@ -109,6 +109,11 @@ namespace Game
extern const dvar_t** version; 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_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source);
extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, 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); 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); 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); int* logfile = reinterpret_cast<int*>(0x1AD8F28);
GamerSettingState* gamerSettings = reinterpret_cast<GamerSettingState*>(0x107D3E8); GamerSettingState* gamerSettings = reinterpret_cast<GamerSettingState*>(0x107D3E8);

View File

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

View File

@ -8900,6 +8900,27 @@ namespace Game
int dataSize; 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 #pragma endregion
#ifndef IDA #ifndef IDA