Skip to content

Input and Output Data

RLMarvin edited this page Jan 9, 2019 · 36 revisions

GameTickPacket

Every tick, your bot will receive a GameTickPacket from the framework. The packet will contain all the raw values from the game (such as car and ball locations). Your bot receives the packet in the get_output(self, packet) function and you should return a ControllerState which describes what your bot's response is.

Getting values from the packet is simple:

def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
    
    # You can get values out of the packet like this:
    x_location_of_first_car = packet.game_cars[0].physics.location.x;

NOTE: Some structs/lists in the GameTickPacket has a fixed length. So make sure you use the num_cars and the num_boosts values as lengths if you iterate through the associated lists.

Sample game tick packet

packet: {
    'game_cars': [
        {
            'physics': {
                'location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
                'rotation': {'pitch': 0.0, 'yaw': 0.0, 'roll': 0.0},
                'velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0},
                'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}
            },
            'score_info': {
                'score': 350,
                'goals': 1,
                'own_goals': 0,
                'assists': 1,
                'saves': 0,
                'shots': 2,
                'demolitions': 0,
            },
            'is_demolished': False,
            'has_wheel_contact': True,
            'is_super_sonic': False,
            'is_bot': True,
            'jumped': False,
            'double_jumped': True,
            'name': 'Jupiter',
            'team': 0,
            'boost': 48.0
        },
        { ... }
    ],
    'num_cars': 2,
    'game_boosts': [
        {
            'is_active': True,
            'timer': 0.0
        },
        { ... }
    ],
    'num_boost': 36,
    'game_ball': {
        'physics': {
            'location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
            'rotation': {'pitch': 0.0, 'yaw': 0.0, 'roll': 0.0},
            'velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0},
            'angular_velocity': {'x': 0.0, 'y': 0.0, 'z': 0.0}
        },
        'latest_touch': {
            'player_name': 'Beavis',
            'time_seconds': 120.63,
            'hit_location': {'x': 0.0, 'y': 0.0, 'z': 0.0},
            'hit_normal': {'x': 0.0, 'y': 0.0, 'z': 0.0}
        },
        'drop_shot_info': {
            'damage_index': 0,
            'absorbed_force': 0,
            'force_accum_recent': 0
        }
    },
    'game_info': {
        'seconds_elapsed': 405.12,
        'game_time_remaining': 34.88,
        'is_overtime': False,
        'is_unlimited_time': False,
        'is_round_active': True,
        'is_kickoff_pause': False,
        'is_match_ended': False,
        'world_gravity_z': -650.0,
        'game_speed': 1.0
    },
    'dropshot_tiles': [
        {
            'tile_state': 0 // UNKNOWN 
        },
        {
            'tile_state': 1 // FILLED 
        },
        {
            'tile_state': 2 // DAMAGED
        },
        {
            'tile_state': 3 // OPEN
        }
    ],
    'num_tiles': 140,
    'teams': [
        {
            'team_index': 0,
            'score': 7
        },
        { ... }
    ],
    'num_teams': 2,
}

ControllerState

A ControllerState is the controller input the bot should perform. Import ControllerState like this: from rlbot.agents.base_agent import SimpleControllerState, and create a new instance with SimpleControllerState()

Example:

from rlbot.agents.base_agent import BaseAgent, SimpleControllerState
from rlbot.utils.structures.game_data_struct import GameTickPacket


class ExampleBot(BaseAgent):
    def initialize_agent(self):
        pass

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        # Make the bot go forwards by setting throttle to 1
        controller = SimpleControllerState()
        controller.throttle = 1
        return controller

The ControllerState has the following attributes:

table ControllerState {
  throttle:float; /// -1 for full reverse, 1 for full forward
  steer:float; /// -1 for full left, 1 for full right
  pitch:float; /// -1 for nose down, 1 for nose up
  yaw:float; /// -1 for full left, 1 for full right
  roll:float; /// -1 for roll left, 1 for roll right
  jump:bool; /// true if you want to press the jump button
  boost:bool; /// true if you want to press the boost button
  handbrake:bool; /// true if you want to press the handbrake button
}

Field Info

A few values are constant, like the locations of boosts and goals. Some of these can be found in the FieldInfo data. FieldInfo contains the following:

field_info: {
    'boost_pads': [
        {
            'location': Vector3,
            'is_full_boost': boolean
        },
        { ... }
    ],
    'num_boosts': int,
    'goals': [
        {
            'team_num': int,
            'location': Vector3,
            'direction': Vector3
        },
        { ... }
    ],
    'num_goals': int
}

Note: Dropshot tiles can be found in FieldInfo as GoalInfo objects. Note2: Boost pads and Dropshot tiles will be sorted according to y * 100 + x, just like their counterparts (game_boosts and dropshot_tiles that contain their current state) in the game tick packet.

In Python, you can retrieve this information by calling get_field_info() on the BaseAgent:

from rlbot.agents.base_agent import BaseAgent, SimpleControllerState
from rlbot.utils.structures.game_data_struct import GameTickPacket

class ExampleBot(BaseAgent):
    def initialize_agent(self):
        pass

    def get_output(self, packet: GameTickPacket) -> SimpleControllerState:
        # Constant values can be found the the FieldInfo:
        info = self.get_field_info()
        
        # Manually construct a list of all big boost pads
        # info.boost_pads has a fixed size but info.num_boosts is how many pads there actually are
        big_pads = []
        for i in range(info.num_boosts):
            pad = info.boost_pads[i]
            if pad.is_full_boost:
                big_pads.append(pad)

Documentation on what it means

You can find descriptions of the tricky values in this file:

https://github.com/RLBot/RLBot/blob/master/src/main/flatbuffers/rlbot.fbs

You will recognize some of the previous mentioned classes as tables. I.e. packet.score_info is a ScoreInfo table.

Clone this wiki locally