From 3da3ef607a0e189266a4cf24e5b0f10efff92962 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Mon, 26 Sep 2022 15:21:19 +1000 Subject: [PATCH] Separate and improve MapReadSizes() Ensure maps with small minimum player count can be selected for voting when player count is low or zero, even if their minimum would otherwise be too high, to reduce chance of maplist fallback (which ignores sizes). Setting (for example) every CTF map to min 4 and every DM map to min 2 is a viable config with this code. Add g_maplist_sizes_specparty, reduces player count used when selecting maps to allow for a consistent spectator population. Better debugging messages. --- qcsrc/common/mapinfo.qc | 17 +++++++++++++++ qcsrc/common/mapinfo.qh | 5 +++++ qcsrc/server/intermission.qc | 40 ++++++++++++++++++------------------ xonotic-server.cfg | 1 + 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/qcsrc/common/mapinfo.qc b/qcsrc/common/mapinfo.qc index c0b67ff4d..23c8d8704 100644 --- a/qcsrc/common/mapinfo.qc +++ b/qcsrc/common/mapinfo.qc @@ -1083,6 +1083,23 @@ int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametyp return r; } +bool MapReadSizes(string map) +{ + // TODO: implement xonotic#28 / xonvote 172 (sizes in mapinfo) + string readsize_msg = strcat("MapReadSizes ", map); + float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ); + if(fh >= 0) + { + map_minplayers = stoi(fgets(fh)); + map_maxplayers = stoi(fgets(fh)); + fclose(fh); + LOG_TRACEF(readsize_msg, ": ok, min %d max %d", map_minplayers, map_maxplayers); + return true; + } + LOG_TRACE(readsize_msg, ": not found"); + return false; +} + float MapInfo_FindName(string s) { // if there is exactly one map of prefix s, return it diff --git a/qcsrc/common/mapinfo.qh b/qcsrc/common/mapinfo.qh index a7bf6ce0a..c2bb5cf44 100644 --- a/qcsrc/common/mapinfo.qh +++ b/qcsrc/common/mapinfo.qh @@ -168,6 +168,11 @@ string MapInfo_BSPName_ByID(float i); // load info about a map by name into the MapInfo_Map_* globals int MapInfo_Get_ByName(string s, float allowGenerate, Gametype gametypeToSet); // 1 on success, 0 on failure, 2 if it autogenerated a mapinfo file +// load map-specific player limits +int map_minplayers; +int map_maxplayers; +bool MapReadSizes(string map); + // look for a map by a prefix, returns the actual map name on success, string_null on failure or ambigous match string MapInfo_FindName_match; // the name of the map that was found float MapInfo_FindName_firstResult; // -1 if none were found, index of first one if not unique but found (FindName then returns -1) diff --git a/qcsrc/server/intermission.qc b/qcsrc/server/intermission.qc index c1a5d33d8..e9c622be4 100644 --- a/qcsrc/server/intermission.qc +++ b/qcsrc/server/intermission.qc @@ -71,32 +71,32 @@ bool MapHasRightSize(string map) return true; // open map size restriction file - string opensize_msg = strcat("opensize ", map); - float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ); + if(!MapReadSizes(map)) + return true; // map has no size restrictions + + string checksize_msg = strcat("MapHasRightSize ", map); int player_limit = ((autocvar_g_maplist_sizes_count_maxplayers) ? GetPlayerLimit() : 0); int pcount = ((player_limit > 0) ? min(player_count, player_limit) : player_count); // bind it to the player limit so that forced spectators don't influence the limits + if(!autocvar_g_maplist_sizes_count_bots) pcount -= currentbots; - if(fh >= 0) + pcount -= rint(cvar("g_maplist_sizes_specparty") * pcount); + + // ensure small maps can be selected when pcount is low + if(map_minplayers <= (_MapInfo_GetTeamPlayBool(MapInfo_CurrentGametype()) ? 4 : 2)) + map_minplayers = 0; + + if(pcount < map_minplayers) { - opensize_msg = strcat(opensize_msg, ": ok, "); - int mapmin = stoi(fgets(fh)); - int mapmax = stoi(fgets(fh)); - fclose(fh); - if(pcount < mapmin) - { - LOG_TRACE(opensize_msg, "not enough"); - return false; - } - if(mapmax && pcount > mapmax) - { - LOG_TRACE(opensize_msg, "too many"); - return false; - } - LOG_TRACE(opensize_msg, "right size"); - return true; + LOG_TRACE(checksize_msg, ": not enough"); + return false; + } + if(map_maxplayers && pcount > map_maxplayers) + { + LOG_TRACE(checksize_msg, ": too many"); + return false; } - LOG_TRACE(opensize_msg, ": not found"); + LOG_TRACE(checksize_msg, ": right size"); return true; } diff --git a/xonotic-server.cfg b/xonotic-server.cfg index 334f749a2..f0937a16d 100644 --- a/xonotic-server.cfg +++ b/xonotic-server.cfg @@ -231,6 +231,7 @@ set g_maplist_check_waypoints 0 "when 1, maps are skipped if there currently are set g_maplist_ignore_sizes 0 "when 1, all maps are shown in the map list regardless of player count" set g_maplist_sizes_count_maxplayers 1 "check the player limit when getting the player count so forced spectators don't affect the size restrictions" set g_maplist_sizes_count_bots 1 "include the number of bots currently in the server when counting the number of players for size restrictions" +set g_maplist_sizes_specparty 0 "this fraction of people are expected to only spectate, reduces player count used to select voting GUI maps" set g_items_mindist 4000 "starting distance for the fading of items" set g_items_maxdist 4500 "maximum distance at which an item can be viewed, after which it will be invisible" -- 2.39.2