1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use crate::{dll::RLBotCoreInterface, interface::RLBotInterface, rlbot::RLBot};
use std::{error::Error, path::PathBuf, thread::sleep, time::Duration};

/// Initializes RLBot and returns a ready-to-use [`RLBot`] object.
///
/// This function works exactly as [`init_with_options`]. Take a look there for
/// more details.
pub fn init() -> Result<RLBot, Box<dyn Error>> {
    init_with_options(Default::default())
}

/// Initializes RLBot and returns a ready-to-use [`RLBot`] object.
///
/// This function will inject the RLBot core DLL into Rocket League, and then
/// load the interface DLL. It might sleep for some time while it waits for
/// RLBot to fully initialize.
///
/// # Panics
///
/// Only one RLBot instance may be created over the life of the application. If
/// you call this function more than once, it will panic. If you lose the RLBot
/// instance, well, you should keep better track of your things.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), Box<::std::error::Error>> {
/// let rlbot = rlbot::init()?;
///
/// rlbot.start_match(&rlbot::MatchSettings::rlbot_vs_allstar("Hero", "Villain"))?;
/// rlbot.wait_for_match_start()?;
///
/// let mut packets = rlbot.packeteer();
/// loop {
///     let packet = packets.next()?;
///     let player_index = 0;
///     let input: rlbot::ControllerState = Default::default();
///     rlbot.update_player_input(player_index, &input)?;
/// }
/// # }
/// ```
///
/// See [`examples/simple`] for a complete example.
///
/// [`examples/simple`]: https://github.com/whatisaphone/rlbot-rust/blob/master/examples/simple.rs
#[allow(clippy::needless_pass_by_value)]
pub fn init_with_options(options: InitOptions) -> Result<RLBot, Box<dyn Error>> {
    let rlbot_dll_directory = options.rlbot_dll_directory.as_ref().map(PathBuf::as_path);

    let dll = RLBotCoreInterface::load(rlbot_dll_directory)?;
    wait_for_initialized(&dll)?;

    Ok(RLBot::new(RLBotInterface::new(dll)))
}

fn wait_for_initialized(dll: &RLBotCoreInterface) -> Result<(), Box<dyn Error>> {
    for _ in 0..100 {
        if (dll.is_initialized)() {
            return Ok(());
        }
        sleep(Duration::from_millis(10));
    }

    Err(From::from("RLBot did not become initialized"))
}

/// Options for customizing the way the framework is initialized.
#[derive(Default)]
pub struct InitOptions {
    rlbot_dll_directory: Option<PathBuf>,
}

impl InitOptions {
    /// Constructs a new `InitOptions`.
    pub fn new() -> Self {
        Self::default()
    }

    /// Sets the directory in which to search for the RLBot DLLs.
    ///
    /// This should be set to the directory containing [these
    /// files][rlbot-dlls]. If this not set, the system's standard DLL search
    /// order will be used.
    ///
    /// [rlbot-dlls]: https://github.com/RLBot/RLBot/tree/cf5ca2794e153eef583eec093c2d9ea6e7afccd9/src/main/python/rlbot/dll
    pub fn rlbot_dll_directory(mut self, rlbot_dll_directory: impl Into<PathBuf>) -> Self {
        self.rlbot_dll_directory = Some(rlbot_dll_directory.into());
        self
    }
}