-
Notifications
You must be signed in to change notification settings - Fork 21
Input and Output Data
Input and output data are controlled by this specification: https://github.com/RLBot/RLBot/blob/master/src/main/flatbuffers/rlbot.fbs
Based on that file, classes are auto-generated in the rlbot.flat
namespace, e.g. rlbot.flat.GameTickPacket
.
As in the C# example, it is strongly recommended that you convert structures like the GameTickPacket into your own internal data structures. Here are some reasons to do so:
- It is generally wise in software engineering to translate to your own business objects. If the framework changes the data format, you will only need to alter your code in one place (the translation), and your complicated bot logic can stay the same.
- The classes in the rlbot.flat namespace are not particularly useful. They have no functions and their read access is a bit slow because the data is stored in a way that you might not expect.
- By using your own version of the structures, you get to avoid the displeasing .Value syntax (nullables) that is generated through FlatBuffers.
The example bot already comes with internal data structures that you can use. These processed structures can be extended to fit your needs, or you can throw them away entirely.
The Bot class (the class that your own bot should inherit) has some useful values that we can read from in order to get some basic information about the car that we are controlling, the team our car is on, and even the name of our car in the game.
These values are public readonly
properties in the Bot class. Some useful values to know are:
this.Team; // The team that our bot is on
this.Name; // Our bot's in-game name
this.Index; // The index of the car our agent is controlling
Note that you don't need to write this
unless there is name shadowing. It was added above to clarify that it is part of the Bot class.
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 GetOutput(GameTickPacket packet)
method and you should return a Controller which describes what your bot's response is. Since GetOutput
is an abstract method in the Bot
class, you must override it.
Getting values from the packet is simple:
public override Controller GetOutput(rlbot.flat.GameTickPacket packet)
{
// Get the location of our car
// It is strongly recommended that you convert rlbot.flat.GameTickPacket into your own internal structure before
// using any game data, or use the processed versions as shown in the example.
rlbot.flat.Vector3 carLocation = rawPacket.Players(this.index)?.Physics?.Location.Value;
...
}
NOTE: Some properties in the GameTickPacket don't implement IEnumerable
as you may expect. For example, GameTickPacket.Players
is not an IEnumerable
but instead a method. To get the length of one of these structures, use the property that specifies the length (e.g. PlayersLength
). This is one of the reasons you should convert everything you use from the GameTickPacket into your own internal data structure! The internal data structure in the example bot uses arrays so IEnumerable
is already implemented for those fields.
Here is a sample GameTickPacket presented in a JSON-like format for clarity.
packet:
{
Players:
[
{
Physics:
{
Location: {X: 0f, Y: 0f, Z: 0f},
Rotation: {Pitch: 0f, Yaw: 0f, Roll: 0f},
Velocity: {X: 0f, Y: 0f, Z: 0f},
AngularVelocity: {X: 0f, Y: 0f, Z: 0f}
},
IsDemolished: false,
HasWheelContact: true,
IsSupersonic: false,
IsBot: true,
Jumped: false,
DoubleJumped: true,
Name: CSharpExample,
Team: 0,
Boost: 48f,
Hitbox: {Length: 118f, Width: 84f, Height: 36f}
},
{ ... }
],
PlayersLength: 2,
BoostPadStates:
[
{
IsActive: true,
Timer: 0f
},
{ ... }
],
BoostPadStatesLength: 36,
Ball:
{
Physics:
{
Location: {X: 0f, Y: 0f, Z: 0f},
Rotation: {Pitch: 0f, Yaw: 0f, Roll: 0f},
Velocity: {X: 0f, Y: 0f, Z: 0f},
AngularVelocity: {X: 0f, Y: 0f, Z: 0f}
},
LatestTouch:
{
PlayerName: CSharpExample (2),
GameSeconds: 120.63f,
Location: {X: 0f, Y: 0f, Z: 0f},
Normal: {X: 0f, Y: 0f, Z: 0f},
Team: 0,
PlayerIndex: 0
},
DropShotInfo:
{
DamageIndex: 0,
AbsorbedForce: 0f,
ForceAccumRecent: 0
}
ShapeType:
{
(enum)
NONE = 0,
BoxShape = 1,
SphereShape = 2,
CylinderShape = 3
}
},
GameInfo:
{
SecondsElapsed: 405.12f,
GameTimeRemaining: 34f,
IsOvertime: false,
IsUnlimitedTime: false,
IsRoundActive: true,
IsKickoffPause: false,
IsMatchEnded: false,
WorldGravityZ: -650f,
GameSpeed: 1f
},
Teams:
[
{
TeamIndex: 0,
Score: 7
},
{ ... }
],
TeamsLength: 2,
}
A Controller is the controller input the bot should perform.
Example:
public override Controller GetOutput(rlbot.flat.GameTickPacket rawPacket)
{
// Return an empty controller with default values
return new Controller();
}
The ControllerState has the following attributes:
{
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
UseItem: bool; // true if you want to use a rumble item
}
A few values are constant, like the locations of boosts and goals. Some of these can be found in the FieldInfo data.
You can retrieve this information by calling GetFieldInfo()
in your class that inherits the Bot class:
public override Controller GetOutput(rlbot.flat.GameTickPacket rawPacket)
{
// Get the locations of all the big boost pads
rlbot.flat.FieldInfo fieldInfo = GetFieldInfo();
Vector3[] boostPads = new Vector3[fieldInfo.BoostPadsLength];
for (int i = 0; i < fieldInfo.BoostPadsLength; i++)
if (fieldInfo.BoostPads(i).Value.IsFullBoost)
boostPads[i] = fieldInfo.BoostPads(i).Value.Location.Value.ToVector3();
...
}
.ToVector3()
can be an extension method that converts rlbot.flat.Vector3
objects to your own Vector3. Here's an example:
public static Vector3 ToVector3(this rlbot.flat.Vector3 vector)
{
return new Vector3(vector.X, vector.Y, vector.Z);
}
FieldInfo contains the following:
FieldInfo:
{
BoostPads:
[
{
Location: {X: -3584f, Y: 0f, Z: 73f},
IsFullBoost: true
},
{ ... }
],
BoostPadsLength: 50,
Goals: [
{
TeamNum: 0,
Location: {X: 0f, Y: 1f, Z: 0f},
Direction: {X: 0f, Y: -5120f, Z: 312f},
},
{ ... }
],
Goals: 2
}
See the central wiki here: https://github.com/RLBot/RLBot/wiki/Dropshot