-
Notifications
You must be signed in to change notification settings - Fork 3
Migration
Legend: β¨=new, π =reworked/changed, β=removed
Instead of using .cfg
files with a format that's only parsed properly by Python,
RLBot v5 now uses the standard .toml
format. This changes makes it easy to grab
your language's off-the-shelf TOML parser to read the configuration file and
get the same data that RLBot would.
To see how TOML works, check out the TOML spec.
todo: example of migrating bot.cfg
to bot.toml
and appearance.cfg
to loadout.toml
In RLBot v5, every bot is now more similar to v4's StandaloneBot
.
This means that your bot MUST run it's run
method at the bottom of the file,
or else IT WILL NOT RUN.
Here is a minimal example of a bot in RLBot v5:
from rlbot.flat import *
from rlbot.managers import Bot
class MyBot(Bot):
def initialize_agent(self):
"""
Called for all heaver initialization that needs to happen.
Field info and match settings are fully loaded at this point, and won't return garbage data.
NOTE: `self.index` is not set at this point, and should not be used. `self.team` and `self.name` _are_ set with correct information.
"""
# A little known feature of even v4,
# bots have a `logger` attribute that can be used to log messages.
self.logger.info("Setting default values that require more match info!")
def get_output(self, packet: GameTickPacket) -> ControllerState:
"""
Where all the logic of your bot gets its input and returns its output.
"""
return ControllerState()
if __name__ == "__main__":
# This is the entry point for the bot.
MyBot().run()
There have been several changes to how you access data like field info, ball prediction, etc.
-
π
def __init__(self, name: str, team: int, index: int)
->def __init__(self)
-
These variables are no longer known at this time.
-
NOTE: This method is similar-ish to the "early start" of v4, but you probably shouldn't use it. If you want to define default variables, the following is more Pythonic:
class MyBot(Bot): my_variable = None counter = 1
These variables can then be accessed like normal via
self.my_variable
andself.counter
.If you need to perform more complex initialization, it's recommended you use
initialize_agent
instead.
-
-
π
initialize_agent
- This method blocks the match from starting until it's finished running. All heavy initialization should be done here, as the purpose of the match not starting is to ensure that all bots had time to boot up and are ready to go. -
π
self.get_field_info()
->self.field_info
- Example:from rlbot.flat import * from rlbot.managers import Bot class MyBot(Bot): def initialize_agent(self): # Log a yellow warning if the number of boost pads is not 34 pads in a standard map! if len(self.field_info.boost_pads) != 34: self.logger.warning( "The standard number of boost pads is 34, but this map has %d:%s", len(self.field_info.boost_pads), "\n".join(map(str, self.field_info.boost_pads)), ) def get_output(self, packet: GameTickPacket) -> ControllerState: return ControllerState() if __name__ == "__main__": MyBot().run()
-
π
self.get_match_settings()
->self.match_settings
- Example:from rlbot.flat import * from rlbot.managers import Bot class MyBot(Bot): gravity = -650 def initialize_agent(self): match self.match_settings.mutator_settings.gravity_option: case GravityOption.Low: self.gravity /= 2 case GravityOption.High: self.gravity *= 1.75 case GravityOption.Super_High: self.gravity *= 5 case GravityOption.Reverse: self.gravity *= -1 def get_output(self, packet: GameTickPacket) -> ControllerState: return ControllerState() if __name__ == "__main__": MyBot().run()
-
π
self.get_ball_prediction_struct()
->self.ball_prediction
-
β
def is_hot_reload_enabled(self) -> bool
- This method is no longer needed, and as such as been removed. -
π
def set_game_state(self, game_state: GameState)
- This method has been replaced by the following, where theGameState
wrapper has been removed:def set_game_state( self, balls: dict[int, DesiredBallState] = {}, cars: dict[int, DesiredCarState] = {}, game_info: Optional[DesiredGameInfoState] = None, commands: list[ConsoleCommand] = [], )
For
balls
andcars
, theint
key is the index of the ball or car you want to modify.Example usage, where the game speed is set to 2x:
from rlbot.flat import DesiredGameInfoState # ... self.set_game_state( game_info=DesiredGameInfoState(game_speed=2) )
-
π QuickChats & MatchComms have been combined into one
-
def handle_quick_chat(self, index: int, team: int, quick_chat: QuickChats)
- This method has been replaced by the following, wherecontent
is abytes
object that contains the message, anddisplay
is an optionalstr
that was owned in-game as a v4 QuickChat used to:from rlbot.flat import * # ... def handle_match_communication( self, index: int, team: int, content: bytes, display: Optional[str], team_only: bool, ): # Be careful with `content`, it can be anything! Make sure to validate it before using it. self.logger.info(f"Received match communication from index {index}! {display}")
-
def send_quick_chat(self, team_only: bool, quick_chat: QuickChats)
->def send_match_comm(self, content: bytes, display: Optional[str] = None, team_only: bool = False)
- Example:from rlbot.flat import * # ... # Print "What a save!" in the chat for all players to see # Note: `b""` is an empty byte string, which is the equivalent of `None` for bytes. # We're using it here to show that we don't need to send any extra data with the message. self.send_match_comm(b"", "What a save!") # Send "15 bot_has_ball" to only our team, with no message to print to the screen self.send_match_comm(b"15 bot_has_ball", team_only=True)
-
- β
num_slices
has been removed due to it not being needed anymore.- The length of the list
slices
is now limited to the number of slices in the prediction. Iterating over the list under the end is now the proper way to access all the data.
- The length of the list
- β
num_boosts
andnum_goals
have been removed due to them not being needed anymore.- The length of the lists
boost_pads
andgoals
are now limited to the number of boosts and goals on the field. Iterating over the lists under the end is now the proper way to access all the data.
- The length of the lists
-
β¨
auto_start_bots
- Whether or not RLBot should automatically start the bots & scripts. If set toFalse
, they will not start until the user manually starts them - HOWEVER, the match will start IMMEDIATELY and will not wait for the bots to connect! -
β¨
script_configurations
- The scripts that are running in the match. -
β¨
freeplay
- Whether or not to start the match in Freeplay instead of a normal Exhibition match. May be useful for testing purposes. -
β¨
launcher
&game_path
- How RLBot should start the game. The options are:-
Launcher.Steam
- Start the game through Steam.-
game_path
does nothing
-
-
Launcher.Epic
- Windows only - Start the game through the Epic Games Store.- No
game_path
required anymore!
- No
-
Launcher.Custom
- Start the game through a custom method. Currently:-
game_path = ""
- The game will not be started by RLBot. -
game_path = "legendary"
- Start the game through the Epic Games Store via the Legendary launcher. Required to use EGS on Linux.
-
-
-
β
game_map
- Usegame_map_upk
instead. If you don't know the file names:import random from rlbot.utils.maps import GAME_MAP_TO_UPK, STANDARD_MAPS # grab random map name from the list STANDARD_MAPS random_map = random.choice(STANDARD_MAPS) # convert the map name to the upk file name game_map_upk = GAME_MAP_TO_UPK[random_map]
-
π
mutator_settings
- New options!Interested in what mutators go with what games modes? Check out this list!
- β¨
multi_ball
MultiBall.One
MultiBall.Two
MultiBall.Four
MultiBall.Six
- β¨
max_time_option
MaxTimeOption.Default
MaxTimeOption.Eleven_Minutes
- β¨
game_event_option
GameEventOption.Default
GameEventOption.Haunted
GameEventOption.Rugby
- β¨
audio_option
AudioOption.Default
AudioOption.Haunted
- π
max_score
- β¨
MaxScore.Seven
- β¨
- π
ball_type_option
- β¨
BallTypeOption.Beachball
- β¨
BallTypeOption.Anniversary
- β¨
BallTypeOption.Haunted
- β¨
BallTypeOption.Ekin
- β¨
BallTypeOption.SpookyCube
- β¨
- π
ball_weight_option
- β¨
BallWeightOption.Curve_Ball
- β¨
BallWeightOption.Beach_Ball_Curve
- β¨
BallWeightOption.Magnus_FutBall
- β¨
- π
ball_size_option
- β¨
BallSizeOption.Medium
- β¨
- π
ball_size_option
- β¨
BallBouncinessOption.LowishBounciness
- β¨
- π
rumble_option
- β¨
RumbleOption.Haunted_Ball_Beam
- β¨
RumbleOption.Tactical
- β¨
RumbleOption.BatmanRumble
- β¨
- π
boost_strength_option
- β¨
BoostStrengthOption.Five
- β¨
- π
gravity_option
- β¨
GravityOption.Reverse
- β¨
- β¨
-
π
game_cars
->players
- π
PlayerInfo
- β¨
latest_touch
- The last time the player touched the ball.- Will be
None
if the player has not touched the ball since the last kickoff. - Contains the
ball_index
of the ball that was touched.
- Will be
- β¨
air_state
- The current state of the car in the air. Possible values are:-
AirState.OnGround
- All 4 wheels are touching the ground. -
AirState.Jumping
- Lasts whilejump
is being held by the player -
AirState.DoubleJumping
- Lasts for ~13 ticks. -
AirState.Dodging
- Lasts for the duration of the torque applied by the dodge, or ~79 ticks. -
AirState.InAir
- The car is in the air, but not in any of the other states.
-
- β¨
dodge_timeout
--1
when the a dodge/double jump is available for an infinite amount of time. This includes when the car in on the ground and when the car fell of a surface and didn't jump. Otherwise, it's the time remaining until the dodge/double jump expires and can no longer be used -0
if a dodge/double jump is currently unavailable. - β¨
last_input
- The last controller input the player used. - β¨
last_spectated
- If the player was the last one to be watched by a spectator - β¨
accolades
- A list of the accolades (as strings) the player earned in the previous tick. Here are some examples of different accolades:-
Win
,Loss
,TimePlayed
-
Shot
,Assist
,Center
,Clear
,PoolShot
-
Goal
,AerialGoal
,BicycleGoal
,BulletGoal
,BackwardsGoal
,LongGoal
,OvertimeGoal
,TurtleGoal
-
AerialHit
,BicycleHit
,BulletHit
,JuggleHit
,FirstTouch
,BallHit
-
Save
,EpicSave
,FreezeSave
-
HatTrick
,Savior
,Playmaker
,MVP
-
FastestGoal
,SlowestGoal
,FurthestGoal
,OwnGoal
-
MostBallTouches
,FewestBallTouches
,MostBoostPickups
,FewestBoostPickups
,BoostPickups
-
CarTouches
,Demolition
,Demolish
-
LowFive
,HighFive
-
- π
is_demolished
->demolished_timeout
--1
if the player is not demolished, otherwise the time remaining until the player respawns. - β
has_wheel_contact
,jumped
, anddouble_jumped
have been removed due to them not being needed anymore.-
has_wheel_contact
is directly replaced byair_state == AirState.OnGround
-
jumped
is directly replaced by checking ifdodge_timeout
is not-1
, which means that the car has jumped. -
double_jumped
is not directly replaced by anything, but ifdodge_timeout
is0
then the car either double jumped, dodged, or the time to do so has expired for the bot.
-
- β¨
- π
-
π
game_boosts
->boost_pads
-
π
game_teams
->teams
-
β
num_cars
,num_boosts
, andnum_teams
have been removed due to them not being needed anymore. -
The length of the lists
players
,boost_pad_states
, andteams
are now limited to the number of cars and boosts in the match. Iterating over the lists under the end is now the proper way to access all the data. -
π
ball
->balls
-balls
is now a list, and RLBot officially supports multiple balls in a single match. However, there are also times in a normal game where this list has 0 items - it's recommended that this is checked for near the start of your logic, so your bot doesn't accidentally throw hundreds of errors.def get_output(self, packet: GameTickPacket) -> ControllerState: if len(packet.balls) == 0: return ControllerState() # Your logic here # ...
-
π
BallInfo
- β
latest_touch
has been removed due to it now being tracked inPlayerInfo
- β
drop_shot_info
has been removed due to RLBot not getting any dropshot data. - π
collision_shape
->shape
-
Old
collision_shape
type:class CollisionShape: type: ShapeType box: BoxShape sphere: SphereShape cylinder: CylinderShape
-
New
shape
type:class CollisionShape: item: Optional[BoxShape | SphereShape | CylinderShape]
-
- β
-
π
game_info
- Several arguments have been replaced bygame_state_type
- β
is_round_active
,is_kickoff_pause
, andis_match_ended
-
is_round_active
is directly replaced bygame_state_type == GameStateType.Active
-
is_kickoff_pause
is directly replaced bygame_state_type == GameStateType.Kickoff
-
is_match_ended
is directly replaced bygame_state_type == GameStateType.Ended
-
- β¨
game_state_type
- The current state of the game. The options are:-
GameStateType.Inactive
- The game is not running. -
GameStateType.Countdown
- The 3.. 2.. 1.. countdown before the a kickoff. -
GameStateType.Kickoff
- After the countdown, but before the game timer starts counting down again. Usually the timer resumes after the ball gets hit by a car. -
GameStateType.Active
- Normal game play. -
GameStateType.GoalScored
- A goal has been scored and the goal animation is playing. -
GameStateType.Replay
- The goal replay is playing. -
GameStateType.Paused
- The game is paused. -
GameStateType.Ended
- The match finished and is on the end screen.
-
- β