From c2f4064bde9f3d501312113a2281df9c7124a96f Mon Sep 17 00:00:00 2001 From: "Dr. Jaska" Date: Tue, 3 Sep 2024 10:57:07 +0000 Subject: [PATCH] Show nextmap on HUD and rewrite nextmap from cvar to cmd --- commands.cfg | 1 + qcsrc/client/hud/panel/scoreboard.qc | 8 ++++++ qcsrc/client/hud/panel/scoreboard.qh | 5 ++++ qcsrc/server/client.qc | 3 +++ qcsrc/server/command/sv_cmd.qc | 37 ++++++++++++++++++++++++++++ qcsrc/server/command/vote.qh | 1 + qcsrc/server/intermission.qc | 29 +++++++++++++++++----- qcsrc/server/intermission.qh | 10 +++++++- qcsrc/server/mapvoting.qc | 12 ++++----- qcsrc/server/world.qc | 3 --- xonotic-client.cfg | 2 ++ xonotic-server.cfg | 1 - 12 files changed, 95 insertions(+), 17 deletions(-) diff --git a/commands.cfg b/commands.cfg index 8ff4e78b8..ae8719a0f 100644 --- a/commands.cfg +++ b/commands.cfg @@ -249,6 +249,7 @@ alias gotomap "qc_cmd_sv gotomap ${* ?}" // Simple alias lockteams "qc_cmd_sv lockteams ${* ?}" // Disable the ability for players to switch or enter teams alias make_mapinfo "qc_cmd_sv make_mapinfo ${* ?}" // Automatically rebuild mapinfo files alias moveplayer "qc_cmd_sv moveplayer ${* ?}" // Change the team/status of a player +alias nextmap "qc_cmd_sv nextmap ${* ?}" // Set/Query the next map alias nospectators "qc_cmd_sv nospectators ${* ?}" // Automatically remove spectators from a match alias printstats "qc_cmd_sv printstats ${* ?}" // Dump eventlog player stats and other score information alias radarmap "qc_cmd_sv radarmap ${* ?}" // Generate a radar image of the map diff --git a/qcsrc/client/hud/panel/scoreboard.qc b/qcsrc/client/hud/panel/scoreboard.qc index d59ed97fe..49a5fac1e 100644 --- a/qcsrc/client/hud/panel/scoreboard.qc +++ b/qcsrc/client/hud/panel/scoreboard.qc @@ -2439,6 +2439,14 @@ void Scoreboard_Draw() sb_gameinfo_type_fontsize = hud_fontsize * 2.5; sb_gameinfo_detail_fontsize = hud_fontsize * 1.3; + if (GET_NEXTMAP() != "") + { + // NOTE: nextmap is drawn before title to avoid covering title in case of long map name + str = strcat("^7", _("Next map:"), " ^9", GET_NEXTMAP()); + drawcolorcodedstring(pos + vec2(hud_fontsize.x * 0.5, sb_gameinfo_type_fontsize.y - hud_fontsize.y * 1.25), + str, hud_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); + } + // Game Info: Game Type if (scoreboard_ui_enabled == 2) str = _("Team Selection"); diff --git a/qcsrc/client/hud/panel/scoreboard.qh b/qcsrc/client/hud/panel/scoreboard.qh index a7cb2b553..fae09910b 100644 --- a/qcsrc/client/hud/panel/scoreboard.qh +++ b/qcsrc/client/hud/panel/scoreboard.qh @@ -5,6 +5,11 @@ bool autocvar_cl_deathscoreboard; string autocvar_scoreboard_columns; float autocvar_hud_panel_scoreboard_namesize = 15; +string autocvar__nextmap; +// no reason for get_nextmap to be a function for now +// macro to not have an unnecessary function call stackframe +#define GET_NEXTMAP() autocvar__nextmap + bool sb_showscores; // set by +showscores engine command bool scoreboard_active; diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index c5dd18268..00d4c0393 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -1222,6 +1222,9 @@ void ClientConnect(entity this) setpause(0); localcmd("\nsv_hook_firstjoin\n"); } + + if (get_nextmap() != "") + Send_NextMap_To_Player(this); } .string shootfromfixedorigin; diff --git a/qcsrc/server/command/sv_cmd.qc b/qcsrc/server/command/sv_cmd.qc index 475f7eb5a..7398329ee 100644 --- a/qcsrc/server/command/sv_cmd.qc +++ b/qcsrc/server/command/sv_cmd.qc @@ -1169,6 +1169,42 @@ void GameCommand_moveplayer(int request, int argc) } } +void GameCommand_nextmap(int request, int argc) +{ + switch (request) + { + case CMD_REQUEST_COMMAND: + { + if (argc >= 2) // nextmap with mapname arg + { + if (argc > 2) + LOG_HELP("Warning: nextmap only takes 1 argument"); + + string map = ValidateMap(argv(1), NULL); + if (map != "" && map != get_nextmap()) + Set_NextMap(map); + } + else // nextmap without args + { + if (get_nextmap() != "") + LOG_HELP(get_nextmap()); + else + LOG_HELP("none"); + } + return; // never fall through to usage + } + + default: + case CMD_REQUEST_USAGE: + { + LOG_HELP("Usage:^3 sv_cmd nextmap []"); + LOG_HELP(" Without arguments it prints current nextmap if one is set"); + LOG_HELP(" With arguments it attempts to set nextmap"); + return; + } + } +} + void GameCommand_nospectators(int request) { switch (request) @@ -1757,6 +1793,7 @@ SERVER_COMMAND(gotomap, "Simple command to switch to another map") { GameCommand SERVER_COMMAND(lockteams, "Disable the ability for players to switch or enter teams") { GameCommand_lockteams(request); } SERVER_COMMAND(make_mapinfo, "Automatically rebuild mapinfo files") { GameCommand_make_mapinfo(request); } SERVER_COMMAND(moveplayer, "Change the team/status of a player") { GameCommand_moveplayer(request, arguments); } +SERVER_COMMAND(nextmap, "Set/Query the next map") { GameCommand_nextmap(request, arguments); } SERVER_COMMAND(nospectators, "Automatically remove spectators from a match") { GameCommand_nospectators(request); } SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); } SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); } diff --git a/qcsrc/server/command/vote.qh b/qcsrc/server/command/vote.qh index 509d4d233..98dec6b7d 100644 --- a/qcsrc/server/command/vote.qh +++ b/qcsrc/server/command/vote.qh @@ -59,6 +59,7 @@ string vote_parsed_display; // visual string which is fixed after being parsed void VoteThink(); void VoteReset(bool verbose); void VoteCommand(int request, entity caller, int argc, string vote_command); +string ValidateMap(string validated_map, entity caller); // warmup and nagger stuff const float RESTART_COUNTDOWN = 10; diff --git a/qcsrc/server/intermission.qc b/qcsrc/server/intermission.qc index 7f11112c1..21d3b9831 100644 --- a/qcsrc/server/intermission.qc +++ b/qcsrc/server/intermission.qc @@ -10,6 +10,21 @@ #include #include +void Send_NextMap_To_Player(entity pl) +{ + stuffcmd(pl, sprintf("\nsettemp _nextmap %s\n", get_nextmap())); +} + +void Set_NextMap(string mapname) +{ + if (mapname != "") + strcpy(_nextmap, mapname); + else + strfree(_nextmap); + + FOREACH_CLIENT(IS_REAL_CLIENT(it), { Send_NextMap_To_Player(it); }); +} + string GetGametype() { return MapInfo_Type_ToString(MapInfo_LoadedGametype); @@ -356,11 +371,12 @@ float DoNextMapOverride(float reinit) alreadychangedlevel = true; return true; } - if(autocvar_nextmap != "") + if(get_nextmap() != "") { string m; - m = GameTypeVote_MapInfo_FixName(autocvar_nextmap); - cvar_set("nextmap",m); + m = GameTypeVote_MapInfo_FixName(get_nextmap()); + if (m != get_nextmap()) + Set_NextMap(m); if(!m || gametypevote) return false; @@ -411,12 +427,13 @@ string GotoMap(string m) if (!m) return "The map you suggested is not available on this server."; if (!autocvar_sv_vote_gametype) - if(!MapInfo_CheckMap(m)) + if (!MapInfo_CheckMap(m)) return "The map you suggested does not support the current game mode."; - cvar_set("nextmap", m); + if (m != get_nextmap()) + Set_NextMap(m); if (!intermission_running) cvar_set("_endmatch", "1"); - if(mapvote_initialized || alreadychangedlevel) + if (mapvote_initialized || alreadychangedlevel) { if(DoNextMapOverride(0)) return "Map switch initiated."; diff --git a/qcsrc/server/intermission.qh b/qcsrc/server/intermission.qh index 44a5a2da8..e1fb0ec8d 100644 --- a/qcsrc/server/intermission.qh +++ b/qcsrc/server/intermission.qh @@ -1,7 +1,15 @@ #pragma once bool autocvar_lastlevel; -string autocvar_nextmap; + +string _nextmap; +void Send_NextMap_To_Player(entity pl); +void Set_NextMap(string mapname); + +// no reason for get_nextmap to be a function for now +// macro to not have an unnecessary function call stackframe +#define get_nextmap() _nextmap + bool autocvar_samelevel; bool autocvar_sv_autoscreenshot; string autocvar_sv_intermission_cdtrack; diff --git a/qcsrc/server/mapvoting.qc b/qcsrc/server/mapvoting.qc index b52f4518d..d94cb1ffa 100644 --- a/qcsrc/server/mapvoting.qc +++ b/qcsrc/server/mapvoting.qc @@ -69,9 +69,9 @@ int GameTypeVote_AvailabilityStatus(string type_name) if( type == NULL ) return flag; - if ( autocvar_nextmap != "" ) + if ( get_nextmap() != "" ) { - if ( !MapInfo_Get_ByName(autocvar_nextmap, false, NULL) ) + if ( !MapInfo_Get_ByName(get_nextmap(), false, NULL) ) return flag; if (!(MapInfo_Map_supportedGametypes & type.gametype_flags)) return flag; @@ -384,7 +384,7 @@ bool MapVote_SendEntity(entity this, entity to, int sf) { // gametype vote WriteByte(MSG_ENTITY, BIT(0)); // gametypevote_flags - WriteString(MSG_ENTITY, autocvar_nextmap); + WriteString(MSG_ENTITY, get_nextmap()); } else if ( autocvar_sv_vote_gametype ) { @@ -496,9 +496,9 @@ bool MapVote_Finished(int mappos) if ( GameTypeVote_Finished(mappos) ) { gametypevote = false; - if(autocvar_nextmap != "") + if(get_nextmap() != "") { - Map_Goto_SetStr(autocvar_nextmap); + Map_Goto_SetStr(get_nextmap()); Map_Goto(0); alreadychangedlevel = true; strfree(voted_gametype_string); @@ -756,7 +756,7 @@ void MapVote_Think() } if(autocvar_sv_vote_gametype) { GameTypeVote_Start(); } - else if(autocvar_nextmap == "") { MapVote_Init(); } + else if(get_nextmap() == "") { MapVote_Init(); } } MapVote_Tick(); diff --git a/qcsrc/server/world.qc b/qcsrc/server/world.qc index effc4d51d..0aee165f1 100644 --- a/qcsrc/server/world.qc +++ b/qcsrc/server/world.qc @@ -310,7 +310,6 @@ void cvar_changes_init() BADCVAR("g_tmayhem_teams"); BADCVAR("g_vip"); BADCVAR("leadlimit"); - BADCVAR("nextmap"); BADCVAR("teamplay"); BADCVAR("timelimit"); BADCVAR("g_mapinfo_q3compat"); @@ -920,8 +919,6 @@ spawnfunc(worldspawn) if(autocvar_sv_eventlog) GameLogInit(); // requires matchid to be set - cvar_set("nextmap", ""); - SetDefaultAlpha(); if(autocvar_g_campaign) diff --git a/xonotic-client.cfg b/xonotic-client.cfg index 4f36583a7..4a0b31314 100644 --- a/xonotic-client.cfg +++ b/xonotic-client.cfg @@ -532,6 +532,8 @@ con_textsize 10 seta sbar_info_pos 0 "Y-axis distance from lower right corner for engine info prints" +set _nextmap "" "internal cvar, automatically synced with server's nextmap" + // scoreboard seta scoreboard_columns default diff --git a/xonotic-server.cfg b/xonotic-server.cfg index 91a54e09a..67f9be443 100644 --- a/xonotic-server.cfg +++ b/xonotic-server.cfg @@ -337,7 +337,6 @@ set sv_eventlog_files_nameprefix xonotic "prefix of individual log file names" set sv_eventlog_files_namesuffix .log "suffix of individual log file names" set sv_eventlog_ipv6_delimiter 0 "use a _ delimiter for IPV6 IPs, so that they can be easily detected in scripts" -set nextmap "" "override the maplist when switching to the next map" set lastlevel "" "for singleplayer use, shows the menu once the match has ended" set quit_when_empty 0 "set to 1, then the server exits when the next level would start but is empty" set quit_and_redirect "" "set to an IP to redirect all players at the end of the match to another server. Set to \"self\" to let all players reconnect at the end of the match (use it to make seamless engine updates)" -- 2.39.2