7
7
from rlbot .utils .os_detector import CURRENT_OS , OS
8
8
9
9
10
- def __parse_enum (table : dict , key : str , enum : Any , default : int = 0 ) -> Any :
10
+ class ConfigParsingException (Exception ):
11
+ pass
12
+
13
+
14
+ def __enum (table : dict , key : str , enum : Any , default : int = 0 ) -> Any :
11
15
if key not in table :
12
- return enum (0 )
16
+ return enum (default )
13
17
try :
14
18
for i in range (100000 ):
15
19
if str (enum (i )).split ('.' )[- 1 ].lower () == table [key ].lower ():
16
20
return enum (i )
17
21
except ValueError :
18
- logger .warning (f"Unknown value '{ table [key ]} ' for key '{ key } ' using default ({ enum (default )} )" )
19
- return enum (default )
22
+ raise ConfigParsingException (f"Invalid value { repr (table [key ])} for key '{ key } '." )
23
+
24
+
25
+ def __str (table : dict , key : str , default : str = "" ) -> str :
26
+ v = table .get (key , default )
27
+ if isinstance (v , str ):
28
+ return v
29
+ raise ConfigParsingException (f"'{ key } ' has value { repr (v )} . Expected a string." )
30
+
31
+
32
+ def __bool (table : dict , key : str , default : bool = False ) -> bool :
33
+ v = table .get (key , default )
34
+ if isinstance (v , bool ):
35
+ return v
36
+ raise ConfigParsingException (f"'{ key } ' has value { repr (v )} . Expected a bool." )
37
+
38
+
39
+ def __int (table : dict , key : str , default : int = 0 ) -> int :
40
+ v = table .get (key , default )
41
+ if isinstance (v , int ):
42
+ return v
43
+ raise ConfigParsingException (f"'{ key } ' has value { repr (v )} . Expected an int." )
44
+
45
+
46
+ def __table (table : dict , key : str ) -> dict :
47
+ v = table .get (key , dict ())
48
+ if isinstance (v , dict ):
49
+ return v
50
+ raise ConfigParsingException (f"'{ key } ' has value { repr (v )} . Expected a table." )
51
+
52
+
53
+ def __team (table : dict ) -> int :
54
+ if 'team' not in table :
55
+ return 0
56
+ v = table ['team' ]
57
+ if isinstance (v , str ):
58
+ if v .lower () == "blue" :
59
+ return 0
60
+ if v .lower () == "orange" :
61
+ return 1
62
+ if isinstance (v , int ):
63
+ if 0 <= v <= 1 :
64
+ return v
65
+ raise ConfigParsingException (f"'team' has value { repr (v )} . Expected a 0, 1, \" blue\" , or \" orange\" ." )
20
66
21
67
22
68
def load_match_config (config_path : Path | str ) -> flat .MatchConfiguration :
@@ -27,90 +73,85 @@ def load_match_config(config_path: Path | str) -> flat.MatchConfiguration:
27
73
with open (config_path , "rb" ) as f :
28
74
config = tomllib .load (f )
29
75
30
- rlbot_table = config . get ( "rlbot" , dict () )
31
- match_table = config . get ( "match" , dict () )
32
- mutator_table = config . get ( "mutators" , dict () )
76
+ rlbot_table = __table ( config , "rlbot" )
77
+ match_table = __table ( config , "match" )
78
+ mutator_table = __table ( config , "mutators" )
33
79
34
80
players = []
35
81
for car_table in config .get ("cars" , []):
36
- car_config = car_table .get ("config_file" )
37
- name = car_table .get ("name" , "" )
38
- team = car_table .get ("team" , 0 )
39
- try :
40
- team = int (team )
41
- except ValueError :
42
- team = {"blue" : 0 , "orange" : 1 }.get (team .lower ())
43
- if team is None or team not in [0 , 1 ]:
44
- logger .warning (f"Unknown team '{ car_table .get ("team" )} ' for player { len (players )} , using default team 0" )
45
-
46
- loadout_file = car_table .get ("loadout_file" )
47
- variant = car_table .get ("type" , "rlbot" )
48
- skill = __parse_enum (car_table , "skill" , flat .PsyonixSkill , int (flat .PsyonixSkill .AllStar ))
82
+ car_config = __str (car_table , "config_file" )
83
+ name = __str (car_table , "name" )
84
+ team = __team (car_table )
85
+ loadout_file = __str (car_table , "loadout_file" ) or None
86
+ skill = __enum (car_table , "skill" , flat .PsyonixSkill , int (flat .PsyonixSkill .AllStar ))
87
+ variant = __str (car_table , "type" , "rlbot" ).lower ()
88
+
49
89
match variant :
50
90
case "rlbot" :
51
- if car_config is None :
52
- loadout = load_player_loadout (loadout_file , team ) if loadout_file else None
53
- players .append (flat .PlayerConfiguration (flat .CustomBot (), name , team , loadout = loadout ))
54
- else :
55
- abs_config_path = (config_path .parent / car_config ).resolve ()
56
- players .append (load_player_config (abs_config_path , flat .CustomBot (), team , name , loadout_file ))
91
+ variety , use_config = flat .CustomBot (), True
57
92
case "psyonix" :
58
- if car_config is None :
59
- loadout = load_player_loadout (loadout_file , team ) if loadout_file else None
60
- players .append (flat .PlayerConfiguration (flat .Psyonix (skill ), name , team , loadout = loadout ))
61
- else :
62
- abs_config_path = (config_path .parent / car_config ).resolve ()
63
- players .append (load_player_config (abs_config_path , flat .Psyonix (skill ), team , name , loadout_file ))
93
+ variety , use_config = flat .Psyonix (skill ), True
64
94
case "human" :
65
- loadout = load_player_loadout (loadout_file , team ) if loadout_file else None
66
- players .append (flat .PlayerConfiguration (flat .Human (), name , team , loadout = loadout ))
95
+ variety , use_config = flat .Human (), False
96
+ case "partymember" :
97
+ logger .warning ("PartyMember player type is not supported yet." )
98
+ variety , use_config = flat .PartyMember , False
99
+ case t :
100
+ raise ConfigParsingException (f"Invalid player type { repr (t )} for player { len (players )} ." )
101
+
102
+ if use_config and car_config :
103
+ abs_config_path = (config_path .parent / car_config ).resolve ()
104
+ players .append (load_player_config (abs_config_path , variety , team , name , loadout_file ))
105
+ else :
106
+ loadout = load_player_loadout (loadout_file , team ) if loadout_file else None
107
+ players .append (flat .PlayerConfiguration (variety , name , team , loadout = loadout ))
67
108
68
109
scripts = []
69
110
for script_table in config .get ("scripts" , []):
70
- if script_config := script_table . get ( "config_file" ):
111
+ if script_config := __str ( script_table , "config_file" ):
71
112
abs_config_path = (config_path .parent / script_config ).resolve ()
72
113
scripts .append (load_script_config (abs_config_path ))
73
114
else :
74
115
scripts .append (flat .ScriptConfiguration ())
75
116
76
117
mutators = flat .MutatorSettings (
77
- match_length = __parse_enum (mutator_table , "match_length" , flat .MatchLengthMutator ),
78
- max_score = __parse_enum (mutator_table , "max_score" , flat .MaxScoreMutator ),
79
- multi_ball = __parse_enum (mutator_table , "multi_ball" , flat .MultiBallMutator ),
80
- overtime = __parse_enum (mutator_table , "overtime" , flat .OvertimeMutator ),
81
- series_length = __parse_enum (mutator_table , "series_length" , flat .SeriesLengthMutator ),
82
- game_speed = __parse_enum (mutator_table , "game_speed" , flat .GameSpeedMutator ),
83
- ball_max_speed = __parse_enum (mutator_table , "ball_max_speed" , flat .BallMaxSpeedMutator ),
84
- ball_type = __parse_enum (mutator_table , "ball_type" , flat .BallTypeMutator ),
85
- ball_weight = __parse_enum (mutator_table , "ball_weight" , flat .BallWeightMutator ),
86
- ball_size = __parse_enum (mutator_table , "ball_size" , flat .BallSizeMutator ),
87
- ball_bounciness = __parse_enum (mutator_table , "ball_bounciness" , flat .BallBouncinessMutator ),
88
- boost_amount = __parse_enum (mutator_table , "boost_amount" , flat .BoostMutator ),
89
- rumble = __parse_enum (mutator_table , "rumble" , flat .RumbleMutator ),
90
- boost_strength = __parse_enum (mutator_table , "boost_strength" , flat .BoostStrengthMutator ),
91
- gravity = __parse_enum (mutator_table , "gravity" , flat .GravityMutator ),
92
- demolish = __parse_enum (mutator_table , "demolish" , flat .DemolishMutator ),
93
- respawn_time = __parse_enum (mutator_table , "respawn_time" , flat .RespawnTimeMutator ),
94
- max_time = __parse_enum (mutator_table , "max_time" , flat .MaxTimeMutator ),
95
- game_event = __parse_enum (mutator_table , "game_event" , flat .GameEventMutator ),
96
- audio = __parse_enum (mutator_table , "audio" , flat .AudioMutator ),
118
+ match_length = __enum (mutator_table , "match_length" , flat .MatchLengthMutator ),
119
+ max_score = __enum (mutator_table , "max_score" , flat .MaxScoreMutator ),
120
+ multi_ball = __enum (mutator_table , "multi_ball" , flat .MultiBallMutator ),
121
+ overtime = __enum (mutator_table , "overtime" , flat .OvertimeMutator ),
122
+ series_length = __enum (mutator_table , "series_length" , flat .SeriesLengthMutator ),
123
+ game_speed = __enum (mutator_table , "game_speed" , flat .GameSpeedMutator ),
124
+ ball_max_speed = __enum (mutator_table , "ball_max_speed" , flat .BallMaxSpeedMutator ),
125
+ ball_type = __enum (mutator_table , "ball_type" , flat .BallTypeMutator ),
126
+ ball_weight = __enum (mutator_table , "ball_weight" , flat .BallWeightMutator ),
127
+ ball_size = __enum (mutator_table , "ball_size" , flat .BallSizeMutator ),
128
+ ball_bounciness = __enum (mutator_table , "ball_bounciness" , flat .BallBouncinessMutator ),
129
+ boost_amount = __enum (mutator_table , "boost_amount" , flat .BoostAmountMutator ),
130
+ rumble = __enum (mutator_table , "rumble" , flat .RumbleMutator ),
131
+ boost_strength = __enum (mutator_table , "boost_strength" , flat .BoostStrengthMutator ),
132
+ gravity = __enum (mutator_table , "gravity" , flat .GravityMutator ),
133
+ demolish = __enum (mutator_table , "demolish" , flat .DemolishMutator ),
134
+ respawn_time = __enum (mutator_table , "respawn_time" , flat .RespawnTimeMutator ),
135
+ max_time = __enum (mutator_table , "max_time" , flat .MaxTimeMutator ),
136
+ game_event = __enum (mutator_table , "game_event" , flat .GameEventMutator ),
137
+ audio = __enum (mutator_table , "audio" , flat .AudioMutator ),
97
138
)
98
139
99
140
return flat .MatchConfiguration (
100
- launcher = __parse_enum (rlbot_table , "launcher" , flat .Launcher ),
101
- launcher_arg = rlbot_table . get ( "launcher_arg" , "" ),
102
- auto_start_bots = rlbot_table . get ( "auto_start_bots" , True ),
103
- game_map_upk = match_table . get ( "game_map_upk" , "" ),
141
+ launcher = __enum (rlbot_table , "launcher" , flat .Launcher ),
142
+ launcher_arg = __str ( rlbot_table , "launcher_arg " ),
143
+ auto_start_bots = __bool ( rlbot_table , "auto_start_bots" , True ),
144
+ game_map_upk = __str ( match_table , "game_map_upk " ),
104
145
player_configurations = players ,
105
146
script_configurations = scripts ,
106
- game_mode = __parse_enum (match_table , "game_mode" , flat .GameMode ),
107
- skip_replays = match_table . get ( "skip_replays" , False ),
108
- instant_start = match_table . get ( "instant_start" , False ),
147
+ game_mode = __enum (match_table , "game_mode" , flat .GameMode ),
148
+ skip_replays = __bool ( match_table , "skip_replays" ),
149
+ instant_start = __bool ( match_table , "instant_start" ),
109
150
mutators = mutators ,
110
- existing_match_behavior = __parse_enum (match_table , "existing_match_behavior" , flat .ExistingMatchBehavior ),
111
- enable_rendering = match_table . get ( "enable_rendering" , False ),
112
- enable_state_setting = match_table . get ( "enable_state_setting" , False ),
113
- freeplay = match_table . get ( "freeplay" , False ),
151
+ existing_match_behavior = __enum (match_table , "existing_match_behavior" , flat .ExistingMatchBehavior ),
152
+ enable_rendering = __bool ( match_table , "enable_rendering" ),
153
+ enable_state_setting = __bool ( match_table , "enable_state_setting" ),
154
+ freeplay = __bool ( match_table , "freeplay" ),
114
155
)
115
156
116
157
@@ -121,34 +162,35 @@ def load_player_loadout(path: Path | str, team: int) -> flat.PlayerLoadout:
121
162
with open (path , "rb" ) as f :
122
163
config = tomllib .load (f )
123
164
124
- loadout = config ["blue_loadout" ] if team == 0 else config ["orange_loadout" ]
165
+ table_name = "blue_loadout" if team == 0 else "orange_loadout"
166
+ loadout = __table (config , table_name )
125
167
paint = None
126
- if paint_table := loadout . get ( "paint" , None ):
168
+ if paint_table := __table ( loadout , "paint" ):
127
169
paint = flat .LoadoutPaint (
128
- car_paint_id = paint_table . get ( "car_paint_id" , 0 ),
129
- decal_paint_id = paint_table . get ( "decal_paint_id" , 0 ),
130
- wheels_paint_id = paint_table . get ( "wheels_paint_id" , 0 ),
131
- boost_paint_id = paint_table . get ( "boost_paint_id" , 0 ),
132
- antenna_paint_id = paint_table . get ( "antenna_paint_id" , 0 ),
133
- hat_paint_id = paint_table . get ( "hat_paint_id" , 0 ),
134
- trails_paint_id = paint_table . get ( "trails_paint_id" , 0 ),
135
- goal_explosion_paint_id = paint_table . get ( "goal_explosion_paint_id" , 0 ),
170
+ car_paint_id = __int ( paint_table , "car_paint_id" ),
171
+ decal_paint_id = __int ( paint_table , "decal_paint_id" ),
172
+ wheels_paint_id = __int ( paint_table , "wheels_paint_id" ),
173
+ boost_paint_id = __int ( paint_table , "boost_paint_id" ),
174
+ antenna_paint_id = __int ( paint_table , "antenna_paint_id" ),
175
+ hat_paint_id = __int ( paint_table , "hat_paint_id" ),
176
+ trails_paint_id = __int ( paint_table , "trails_paint_id" ),
177
+ goal_explosion_paint_id = __int ( paint_table , "goal_explosion_paint_id" ),
136
178
)
137
179
138
180
return flat .PlayerLoadout (
139
- team_color_id = loadout . get ( "team_color_id" , 0 ),
140
- custom_color_id = loadout . get ( "custom_color_id" , 0 ),
141
- car_id = loadout . get ( "car_id" , 0 ),
142
- decal_id = loadout . get ( "decal_id" , 0 ),
143
- wheels_id = loadout . get ( "wheels_id" , 0 ),
144
- boost_id = loadout . get ( "boost_id" , 0 ),
145
- antenna_id = loadout . get ( "antenna_id" , 0 ),
146
- hat_id = loadout . get ( "hat_id" , 0 ),
147
- paint_finish_id = loadout . get ( "paint_finish_id" , 0 ),
148
- custom_finish_id = loadout . get ( "custom_finish_id" , 0 ),
149
- engine_audio_id = loadout . get ( "engine_audio_id" , 0 ),
150
- trails_id = loadout . get ( "trails_id" , 0 ),
151
- goal_explosion_id = loadout . get ( "goal_explosion_id" , 0 ),
181
+ team_color_id = __int ( loadout , "team_color_id" ),
182
+ custom_color_id = __int ( loadout , "custom_color_id" ),
183
+ car_id = __int ( loadout , "car_id" ),
184
+ decal_id = __int ( loadout , "decal_id" ),
185
+ wheels_id = __int ( loadout , "wheels_id" ),
186
+ boost_id = __int ( loadout , "boost_id" ),
187
+ antenna_id = __int ( loadout , "antenna_id" ),
188
+ hat_id = __int ( loadout , "hat_id" ),
189
+ paint_finish_id = __int ( loadout , "paint_finish_id" ),
190
+ custom_finish_id = __int ( loadout , "custom_finish_id" ),
191
+ engine_audio_id = __int ( loadout , "engine_audio_id" ),
192
+ trails_id = __int ( loadout , "trails_id" ),
193
+ goal_explosion_id = __int ( loadout , "goal_explosion_id" ),
152
194
loadout_paint = paint ,
153
195
)
154
196
@@ -165,29 +207,30 @@ def load_player_config(
165
207
with open (path , "rb" ) as f :
166
208
config = tomllib .load (f )
167
209
168
- settings : dict [ str , Any ] = config [ "settings" ]
210
+ settings = __table ( config , "settings" )
169
211
170
212
root_dir = path .parent .absolute ()
171
213
if "root_dir" in settings :
172
- root_dir /= Path (settings [ "root_dir" ] )
214
+ root_dir /= Path (__str ( settings , "root_dir" ) )
173
215
174
- run_command = settings . get ( "run_command" , "" )
216
+ run_command = __str ( settings , "run_command " )
175
217
if CURRENT_OS == OS .LINUX and "run_command_linux" in settings :
176
- run_command = settings [ "run_command_linux" ]
218
+ run_command = __str ( settings , "run_command_linux" )
177
219
178
- loadout_path = path .parent / Path (settings ["loadout_file" ]) if "loadout_file" in settings else loadout_override
220
+ loadout_path = path .parent / Path (__str (settings , "loadout_file" )) if "loadout_file" in settings else None
221
+ loadout_path = loadout_override or loadout_path
179
222
loadout = load_player_loadout (loadout_path , team ) if loadout_path is not None else None
180
223
181
224
return flat .PlayerConfiguration (
182
225
type ,
183
- settings . get ( "name" , name_override or "Unnamed " ),
226
+ name_override or __str ( settings , "name " ),
184
227
team ,
185
228
str (root_dir ),
186
- str ( run_command ) ,
229
+ run_command ,
187
230
loadout ,
188
231
0 ,
189
- settings . get ( "agent_id" , "" ),
190
- settings . get ( "hivemind" , False ),
232
+ __str ( settings , "agent_id " ),
233
+ __bool ( settings , "hivemind" ),
191
234
)
192
235
193
236
@@ -203,16 +246,16 @@ def load_script_config(path: Path | str) -> flat.ScriptConfiguration:
203
246
204
247
root_dir = path .parent
205
248
if "root_dir" in settings :
206
- root_dir /= Path (settings [ "root_dir" ] )
249
+ root_dir /= Path (__str ( settings , "root_dir" ) )
207
250
208
- run_command = settings . get ( "run_command" , "" )
251
+ run_command = __str ( settings , "run_command " )
209
252
if CURRENT_OS == OS .LINUX and "run_command_linux" in settings :
210
- run_command = settings [ "run_command_linux" ]
253
+ run_command = __str ( settings , "run_command_linux" )
211
254
212
255
return flat .ScriptConfiguration (
213
- settings . get ( "name" , "Unnamed " ),
256
+ __str ( settings , "name " ),
214
257
str (root_dir ),
215
258
run_command ,
216
259
0 ,
217
- settings . get ( "agent_id" , "" ),
260
+ __str ( settings , "agent_id " ),
218
261
)
0 commit comments