# rlbot-rust
[![crates.io](https://img.shields.io/crates/v/rlbot.svg)](https://crates.io/crates/rlbot)
[![docs](https://docs.rs/rlbot/badge.svg)](https://docs.rs/rlbot/)
[![Build Status](https://travis-ci.org/whatisaphone/rlbot-rust.svg?branch=master)](https://travis-ci.org/whatisaphone/rlbot-rust)
[RLBot] is a framework for creating offline Rocket League bots. This crate lets
you write bots using a simple, safe interface that should feel comfortable to
Rust developers.
**Documentation:** [We have it.](https://docs.rs/rlbot/)
**Stability:** As you might notice, we're still on version 0.x. Breaking changes
are still possible at this stage. Join the [Discord] to keep up-to-date!
**Compatibility**: We target the latest version of RLBot, and the latest stable
version of Rust.
[RLBot]: https://github.com/RLBot/RLBot
[Discord]: https://discordapp.com/invite/XhrQGf
## Usage
Your code will look a little something like this:
```rust
use rlbot::ffi;
fn main() -> Result<(), Box> {
rlbot::run_bot(MyBot { /* ... */ })
}
struct MyBot { /* ... */ }
impl rlbot::Bot for MyBot {
fn tick(&mut self, packet: &ffi::LiveDataPacket) -> ffi::PlayerInput {
// ...
}
}
```
This library comes with plenty of examples to get you started. For a list of
examples, check out the [docs].
[docs]: https://docs.rs/rlbot/
### Installing the framework
RLBot is needed to use this RLBot binding, of course. If the framework is not
found in any of Windows's [DLL search locations], `init()` will return this
error:
[DLL search locations]: https://docs.microsoft.com/en-us/windows/desktop/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications
```text
Os { code: 2, kind: NotFound, message: "The system cannot find the file specified." }
```
RLBot is written in Python, so the easiest way to get the needed files is to use
`pip`:
```sh
pip install rlbot
```
Then add them to your `PATH` (adapt this command to the location of `rlbot` on
your particular system:
```sh
export PATH="$PATH":/c/Python36/Lib/site-packages/rlbot/dll
```
## Development
### Prerequisites
* Use [rustup] to install both stable Rust and nightly Rust.
This library targets stable Rust, however nightly Rust is needed for a few
development niceties like `cargo fmt` and `cargo doc`.
* Install [pre-commit], and run this command:
```sh
pre-commit install
```
This makes it much less likely that your commits will break the build.
[rustup]: https://rustup.rs/
[pre-commit]: https://pre-commit.com/
### Testing
Many of the tests require a copy of Rocket League. All such tests will have
`integration` in their name. Because these tests cannot be run in CI, they
should be run manually before cutting a release, using this command:
```sh
cargo test -- integration
```
### How to compile the flatbuffer schema
Flatbuffers comes with a schema compiler, flatc. Unless your package manager
has flatc and allows building HEAD, you'll have to [build flatc] yourself.
Get the most recent [flatbuffer schema]. Then compile the schema like so from
this project's root:
```sh
flatc -o src --rust rlbot.fbs
cargo fix --allow-dirty
cargo +nightly fmt
```
This will update the `src/rlbot_generated.rs` file.
[build flatc]: https://google.github.io/flatbuffers/flatbuffers_guide_building.html
[flatbuffer schema]: https://github.com/RLBot/RLBot/blob/master/src/main/flatbuffers/rlbot.fbs
### How to generate ffi bindings
Bindings are generated with [rust-bindgen]. Those docs are required reading.
[rust-bindgen]: https://rust-lang-nursery.github.io/rust-bindgen/
After bindgen and its prerequisites are installed and working, run this
delightfully short command:
```sh
rlbot=
bindgen \
cpp/rlbot.hpp \
-o src/ffi.rs \
--disable-name-namespacing \
--no-layout-tests \
--default-enum-style rust \
--with-derive-default \
--raw-line '#![allow(non_camel_case_types, non_snake_case, missing_docs)]' \
--whitelist-function BallPrediction::GetBallPrediction \
--whitelist-function BallPrediction::GetBallPredictionStruct \
--whitelist-function GameFunctions::Free \
--whitelist-function GameFunctions::SetGameState \
--whitelist-function GameFunctions::StartMatch \
--whitelist-function GameFunctions::StartMatchFlatbuffer \
--whitelist-function GameFunctions::UpdateFieldInfoFlatbuffer \
--whitelist-function GameFunctions::UpdateFieldInfo \
--whitelist-function GameFunctions::UpdateLiveDataPacketFlatbuffer \
--whitelist-function GameFunctions::UpdateLiveDataPacket \
--whitelist-function GameFunctions::UpdateRigidBodyTickFlatbuffer \
--whitelist-function GameFunctions::UpdateRigidBodyTick \
--whitelist-function GameFunctions::SendQuickChat \
--whitelist-function GameFunctions::SendChat \
--whitelist-function GameFunctions::UpdatePlayerInput \
--whitelist-function GameFunctions::UpdatePlayerInputFlatbuffer \
--whitelist-function Interface::IsInitialized \
--whitelist-function RenderFunctions::RenderGroup \
-- \
-fdeclspec \
-I "$rlbot"/src/main/cpp/RLBotInterface/RLBotInterface \
-I "$rlbot"/src/main/cpp/RLBotInterface/RLBotMessages
```
It should output errors in white text. Modify RLBot's source to fix the errors.
If on an OS that uses forward slashes (ie not Windows), this can quickly
alleviate some of the pain, run from the `RLBotInterface` directory:
```sh
find . | xargs perl -pi -e 's/([\w\.])\\(\w)/$1\/$2/g'
```
Commenting out includes that may fail to resolve:
```sh
find . | xargs perl -pi -e 's/\#include \/\/\//g'
```
For any problematic references to boost, it will be easiest to just purge
indiscriminately. You may have to remove other things, like everything to do
with `MessageStorage`, `GameInput`, `RenderOutput` and `CallbackOutput`. Keep
running the above bindgen command and fixing errors (fun times!). After you've
subjected yourself to enough pain, it will run successfully and output more
errors, but in red text this time. As long as the errors are in red, that means
it worked!
Now open the resulting file (`src/ffi.rs`) and delete all the `extern "C" pub
fn` declarations at the end. Since the DLL is actually loaded using this
crate's `dll` module, there's no sense exposing the non-working functions—it
would just lead to confusion.