From 2d7713a51f06f8432f3268d3efec87da94eed91c Mon Sep 17 00:00:00 2001 From: RebelNode Date: Sun, 24 Sep 2023 19:12:43 +0300 Subject: [PATCH] Automatically update nextmap mapLists.conf (#128) Adds functionality wanted in https://github.com/beyond-all-reason/maps-metadata/issues/118 --- .github/workflows/ci.yaml | 1 + Makefile | 5 +- map_list.schema.yaml | 4 + scripts/py/gen_nextmap_maplists.py | 142 +++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 scripts/py/gen_nextmap_maplists.py diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d0631d6..9c30958 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -152,6 +152,7 @@ jobs: - name: Patch SPADS Config run: | cp gen/mapBoxes.conf spads_config_bar/etc/mapBoxes.conf + cp gen/mapLists.conf spads_config_bar/etc/mapLists.conf - name: Commit and push run: | cd spads_config_bar diff --git a/Makefile b/Makefile index d01b2ab..1984645 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Default target ran by make -all: gen/map_list.validated.json gen/mapDetails.lua gen/live_maps.validated.json gen/mapBoxes.conf +all: gen/map_list.validated.json gen/mapDetails.lua gen/live_maps.validated.json gen/mapBoxes.conf gen/mapLists.conf # Rules for doing generic data files conversion, e.g yaml to json gen/%.json: %.yaml @@ -25,6 +25,9 @@ gen/live_maps.json: gen/map_list.validated.json gen/types/map_list.d.ts gen/cdn_ gen/mapBoxes.conf: gen/map_list.validated.json gen/types/map_list.d.ts ts-node scripts/js/src/gen_map_boxes_conf.ts $@ +gen/mapLists.conf: gen/map_list.validated.json + python scripts/py/gen_nextmap_maplists.py + # Tests on data test: typecheck_scripts check_startboxes echo ok diff --git a/map_list.schema.yaml b/map_list.schema.yaml index 0ef8785..73ce4c8 100644 --- a/map_list.schema.yaml +++ b/map_list.schema.yaml @@ -92,6 +92,10 @@ additionalProperties: additionalProperties: false required: - poly + maxPlayersPerStartbox: + type: integer + minimum: 1 + maximum: 8 additionalProperties: false required: - startboxes diff --git a/scripts/py/gen_nextmap_maplists.py b/scripts/py/gen_nextmap_maplists.py new file mode 100644 index 0000000..5a80055 --- /dev/null +++ b/scripts/py/gen_nextmap_maplists.py @@ -0,0 +1,142 @@ +# Generates maplists for https://github.com/beyond-all-reason/spads_config_bar/blob/main/etc/mapLists.conf . This controls the !nextmap command in spads. + +import json +import math + +teamsizes = ['2v2','3v3','4v4','5v5','6v6','7v7','8v8','ffa3','ffa4','ffa5','ffa6','ffa7','ffa8','ffa9','ffa10','ffa11','ffa12','ffa13','ffa14','ffa15','ffa16','2v2v2','2v2v2v2','2v2v2v2v2','2v2v2v2v2v2','2v2v2v2v2v2v2','2v2v2v2v2v2v2v2','3v3v3','3v3v3v3','3v3v3v3v3','4v4v4','4v4v4v4','5v5v5'] + +def get_data(input_file): + with open(input_file) as f: + contents = json.load(f) + + teamsize_dict = {} + certified_maps = [] + uncertified_maps = [] + maps_1v1 = [] + + for i in teamsizes: + teamsize_dict[i] = [] + + for map in contents.values(): + if not map["inPool"]: + continue + is_team = False + mapname = '' + player_count = 0 + + + mapname = map["springName"] + is_team = "team" in map["gameType"] + + if "playerCount" in map: + player_count = map["playerCount"] + #32 player ffa or other such sillyness not supported in !nextmap + if player_count > 16: + player_count = 16 + if player_count < 2: + player_count = 2 + + if "startboxesSet" in map: + for startboxes_info in map["startboxesSet"].values(): + if "maxPlayersPerStartbox" in startboxes_info: + team_count = len(startboxes_info["startboxes"]) + max_players_per_startbox = startboxes_info["maxPlayersPerStartbox"] + + # add non-ffa maps to teamsize_dict + if team_count*max_players_per_startbox <= 16: + for x in range(2,max_players_per_startbox+1): + if x >= math.floor(max_players_per_startbox/2): + teamsize_dict['v'.join([str(x)] * team_count)].append(mapname) + + # if a map didn't have "maxPlayersPerStartbox" set for its startboxes, but it's a teamgame map with startboxes for 2 teams, we'll use playerCount instead: + if not "maxPlayersPerStartbox" in startboxes_info and player_count and is_team: + team_count = len(startboxes_info["startboxes"]) + if team_count == 2 and player_count >=4: + for x in range(2,math.floor(player_count/2)+1): + if x >= math.floor(player_count/4): + teamsize_dict['v'.join([str(x)] * team_count)].append(mapname) + + # add ffa maps to teamsize_dict + if "ffa" in map["gameType"]: + for x in range(3,17): + if x <= player_count and x >= math.floor(player_count/2): + teamsize_dict['ffa' + str(x)].append(mapname) + + # add maps to certified and uncertified lists + if map["certified"]: + certified_maps.append(mapname) + else: + uncertified_maps.append(mapname) + + # add maps to 1v1 list + if "1v1" in map["gameType"]: + maps_1v1.append(mapname) + + # make the lists more human-readable + for maplist in teamsize_dict.values(): + maplist.sort() + + certified_maps.sort() + uncertified_maps.sort() + maps_1v1.sort() + + # if combined_dict has empty lists then add ".*" (meaning all maps) to that list + for i in teamsize_dict: + if len(teamsize_dict[i]) == 0: + teamsize_dict[i].append('.*') + + return teamsize_dict, certified_maps, uncertified_maps, maps_1v1 + +def get_output_string(teamsize_dict, certified_maps, uncertified_maps, maps_1v1): + nl = '\n' + output_string = f"""# This file was automatically generated by https://github.com/beyond-all-reason/maps-metadata/tree/main/scripts/py/gen_nextmap_maplists.py using data from rowy. +# Next update from rowy will overwrite this file so do not manually edit this file. +# If you want to make updates to this see https://github.com/beyond-all-reason/maps-metadata/wiki/Adding-a-created-map-to-the-game. +# A map needs properly configured playercount, startboxes and maxPlayersPerStartbox in https://rowy.beyondallreason.dev/table/maps to appear here. +# For example a 2v2v2v2 map needs a startbox configuration with 4 startboxes and maxPlayersPerStartbox >= 2. +[all] +.* + +[certified] +{nl.join(certified_maps)} + +[uncertified] +{nl.join(uncertified_maps)} + +[small] +.* + +[medium] +.* + +[large] +.* + +[extraLarge] +.* + +[misc] +.* + +[1v1] +{nl.join(maps_1v1)} + +""" + + for i in teamsize_dict: + output_string = output_string + '[' + i + ']\n' + output_string += '\n'.join(teamsize_dict[i]) + output_string = output_string + '\n\n' + + return output_string + +def process(input_file,output_file): + teamsize_dict, certified_maps, uncertified_maps, maps_1v1 = get_data(input_file) + output = get_output_string(teamsize_dict, certified_maps, uncertified_maps, maps_1v1) + with open(output_file, "w") as f: + f.write(output) + +if __name__ == '__main__': + input_file = './gen/map_list.validated.json' + output_file = './gen/mapLists.conf' + process(input_file, output_file)