1313
1414from rcon import maps
1515from rcon .cache_utils import get_redis_client
16- from rcon .maps import categorize_maps , numbered_maps , sort_maps_by_gamemode
16+ from rcon .maps import (
17+ Environment ,
18+ GameMode ,
19+ categorize_maps ,
20+ sort_maps_by_gamemode ,
21+ )
1722from rcon .models import PlayerID , PlayerOptins , enter_session
1823from rcon .player_history import get_player
1924from rcon .rcon import CommandFailedError , Rcon , get_rcon
@@ -482,7 +487,9 @@ def handle_vote_command(self, struct_log: StructuredLogLineWithMetaData) -> bool
482487 cmd_handler = VoteMapCommandHandler (self , self ._rcon , self ._config_loader ())
483488 return cmd_handler .execute (struct_log , player_id )
484489
485- def register_vote (self , player_id : str , timestamp : int , entry : int , count : int | None = None ):
490+ def register_vote (
491+ self , player_id : str , timestamp : int , entry : int , count : int | None = None
492+ ):
486493 """
487494 Checks whether the player exists, the vote is not too old and
488495 if there is any game going on.\n
@@ -541,7 +548,9 @@ def register_vote(self, player_id: str, timestamp: int, entry: int, count: int |
541548 # Check for player's flags
542549 # Pick the one with the lowest vote_count
543550 else :
544- player_flags = list (map (lambda flag_record : flag_record ["flag" ], player ["flags" ]))
551+ player_flags = list (
552+ map (lambda flag_record : flag_record ["flag" ], player ["flags" ])
553+ )
545554 config_flags = self ._config_loader ().vote_flags
546555 flag_vote_counts = []
547556 for flag in config_flags :
@@ -578,7 +587,7 @@ def register_vote(self, player_id: str, timestamp: int, entry: int, count: int |
578587 return selected_map_id
579588
580589 @validate_map_ids
581- def register_player_choice (self , map_id : str , player_id : str , player_name : str ):
590+ def register_player_choice (self , map_id : str , player_id : str ):
582591 if self .get_player_choice ():
583592 raise Exception ("Player's map choice was already selected." )
584593
@@ -606,6 +615,8 @@ def register_player_choice(self, map_id: str, player_id: str, player_name: str):
606615 f"Map choice not registered!\n Something went wrong while searching for your { player_id = } profile."
607616 )
608617
618+ player_name = player ["names" ][0 ]["name" ]
619+
609620 self ._state .set_player_choice (player_id , player_name )
610621 # Access state's method directly to prevent sorting by game mode
611622 self ._state .set_selection ([map_id ] + selection )
@@ -911,7 +922,10 @@ class VoteMapCommandHandler:
911922 SHOW_CMD_PATTERN = re .compile (r"(!votemap|!vm)$" , re .IGNORECASE )
912923 NEVER_CMD_PATTERN = re .compile (r"(!votemap|!vm)\s*never$" , re .IGNORECASE )
913924 ALLOW_CMD_PATTERN = re .compile (r"(!votemap|!vm)\s*allow$" , re .IGNORECASE )
914- CHOICE_CMD_PATTERN = re .compile (r"(!votemap|!vm)\s*add$" , re .IGNORECASE )
925+ CHOICE_HELP_CMD_PATTERN = re .compile (r"(!votemap|!vm)\s*add\s*help$" , re .IGNORECASE )
926+ CHOICE_CMD_PATTERN = re .compile (
927+ r"(!votemap|!vm)\s*add\s+(\w{3}\s+\w+\s+\w+|\w{3}\s+\w+|\w{3})" , re .IGNORECASE
928+ )
915929
916930 def __init__ (self , votemap : VoteMap , rcon : Rcon , config : VoteMapUserConfig ):
917931 self .votemap = votemap
@@ -934,8 +948,11 @@ def execute(self, log: StructuredLogLineWithMetaData, player_id: str):
934948 self .handle_opt_out (player_id )
935949 elif self .ALLOW_CMD_PATTERN .match (message ):
936950 self .handle_opt_in (player_id )
937- elif self .CHOICE_CMD_PATTERN .match (message ):
938- self .handle_player_choice (player_id , log )
951+ elif self .CHOICE_HELP_CMD_PATTERN .match (message ):
952+ self .handle_player_choice_help (player_id )
953+ elif match := self .CHOICE_CMD_PATTERN .match (message ):
954+ args = match .group (2 ).lower ().split ()
955+ self .handle_player_choice (player_id , * args )
939956 else :
940957 # fallback
941958 message = "INVALID COMMAND!\n " + (
@@ -948,9 +965,78 @@ def execute(self, log: StructuredLogLineWithMetaData, player_id: str):
948965
949966 return True
950967
951- # TODO
952- def handle_player_choice (self , player_id : str , log : StructuredLogLineWithMetaData ):
953- pass
968+ def handle_player_choice_help (self , player_id : str ):
969+ all_maps = self .rcon .get_maps ()
970+ tag_to_id = {m .map .tag : m .map .shortname for m in all_maps }
971+ environments = [weather .value for weather in Environment ]
972+ game_modes = [mode .value for mode in GameMode ]
973+
974+
975+ help_text = "How to add your map?"
976+ help_text += "\n \n Type in the chat:\n '!vm add <map_tag> [game_mode] [environment]'"
977+ help_text += "\n Defaults: game_mode=warfare, environment=day"
978+ help_text += "\n eg. '!vm add car' -> carentan warfare day"
979+ help_text += "\n \n MAP_TAG options:"
980+ help_text += "\n " + "\n " .join (f"{ key } -> { value } " for key , value in tag_to_id .items ())
981+ help_text += "\n \n GAME_MODE options:"
982+ help_text += "\n " + "\n " .join (game_modes )
983+ help_text += "\n \n ENVIRONMENT options:"
984+ help_text += "\n " + "\n " .join (environments )
985+
986+ self .rcon .message_player (player_id = player_id , message = help_text )
987+
988+ def handle_player_choice (
989+ self ,
990+ player_id : str ,
991+ map_tag : str ,
992+ game_mode : str = "warfare" ,
993+ environment : str = "day" ,
994+ ):
995+ all_maps = self .rcon .get_maps ()
996+ tag_to_id = {m .map .tag : m .map .shortname for m in all_maps }
997+ environments = [weather .value for weather in Environment ]
998+ game_modes = [mode .value for mode in GameMode ]
999+
1000+ if map_tag .upper () not in tag_to_id :
1001+ raise Exception (
1002+ f"""INVALID MAP\n
1003+ OPTIONS:\n \
1004+ { "\n " .join (f"{ key } -> { value } " for key , value in tag_to_id .items ())} """
1005+ )
1006+
1007+ if game_mode not in game_modes :
1008+ raise Exception (
1009+ f"""INVALID GAME MODE\n
1010+ OPTIONS:\n \
1011+ { "\n " .join (game_modes )} """
1012+ )
1013+
1014+ if environment not in environments :
1015+ raise Exception (
1016+ f"""INVALID ENVIRONMENT\n
1017+ OPTIONS:\n
1018+ { "\n " .join (environments )} """
1019+ )
1020+
1021+ map_found = list (filter (
1022+ lambda m : m .map .tag == map_tag .upper ()
1023+ and m .game_mode == game_mode
1024+ and m .environment == environment ,
1025+ all_maps ,
1026+ ))
1027+
1028+ if len (map_found ) == 0 :
1029+ raise Exception (
1030+ f"""INVALID OPTIONS\n
1031+ The map with the given options does not exist.\n
1032+ OPTIONS:\n
1033+ { "\n " .join ([f"{ map_tag = } " , f"{ game_mode = } " , f"{ environment = } " ])} """
1034+ )
1035+
1036+ map_choice = map_found [0 ]
1037+ self .votemap .register_player_choice (map_choice .id , player_id )
1038+ success_msg = f"SUCCESS\n \n Map selected:\n { map_choice .pretty_name } \n Type !vm too see the new selection"
1039+ self .rcon .message_player (player_id = player_id , message = success_msg )
9541040
9551041 def handle_vote (
9561042 self , player_id : str , log : StructuredLogLineWithMetaData , entry : int
@@ -1240,6 +1326,7 @@ class VoteMapNoInitialised(Exception):
12401326class PlayerNotFound (Exception ):
12411327 pass
12421328
1329+
12431330class PlayerVoteMapBan (Exception ):
12441331 def __init__ (self , message = "Player is banned from voting" ):
1245- super ().__init__ (message )
1332+ super ().__init__ (message )
0 commit comments