use crate::{dll::RLBotCoreInterface, error::RLBotError, ffi, flat};
use std::{
os::raw::{c_int, c_void},
ptr::null_mut,
slice,
};
pub struct RLBotInterface {
dll: RLBotCoreInterface,
}
impl RLBotInterface {
pub fn new(dll: RLBotCoreInterface) -> Self {
Self { dll }
}
pub fn update_field_info_flatbuffer<'fb>(&self) -> Option<flat::FieldInfo<'fb>> {
let byte_buffer = (self.dll.update_field_info_flatbuffer)();
get_flatbuffer::<flat::FieldInfo<'_>>(byte_buffer)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn update_field_info(&self, field_info: &mut ffi::FieldInfo) -> Result<(), RLBotError> {
let status = (self.dll.update_field_info)(field_info);
core_result(status)
}
pub fn update_live_data_packet_flatbuffer<'fb>(&self) -> Option<flat::GameTickPacket<'fb>> {
let byte_buffer = (self.dll.update_live_data_packet_flatbuffer)();
get_flatbuffer::<flat::GameTickPacket<'_>>(byte_buffer)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn update_live_data_packet(
&self,
packet: &mut ffi::LiveDataPacket,
) -> Result<(), RLBotError> {
let status = (self.dll.update_live_data_packet)(packet);
core_result(status)
}
pub fn update_rigid_body_tick_flatbuffer<'fb>(&self) -> Option<flat::RigidBodyTick<'fb>> {
let byte_buffer = (self.dll.update_rigid_body_tick_flatbuffer)();
get_flatbuffer::<flat::RigidBodyTick<'_>>(byte_buffer)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn update_rigid_body_tick(&self, tick: &mut ffi::RigidBodyTick) -> Result<(), RLBotError> {
let status = (self.dll.update_rigid_body_tick)(tick);
core_result(status)
}
pub fn set_game_state(&self, desired_game_state_buffer: &[u8]) -> Result<(), RLBotError> {
let status = (self.dll.set_game_state)(
desired_game_state_buffer.as_ptr() as *mut c_void,
desired_game_state_buffer.len() as c_int,
);
core_result(status)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn start_match(&self, match_settings: ffi::MatchSettings) -> Result<(), RLBotError> {
let status = (self.dll.start_match)(match_settings, None, null_mut());
core_result(status)
}
pub fn start_match_flatbuffer(&self, match_settings_buffer: &[u8]) -> Result<(), RLBotError> {
let status = (self.dll.start_match_flatbuffer)(
match_settings_buffer.as_ptr() as *mut c_void,
match_settings_buffer.len() as c_int,
);
core_result(status)
}
pub fn send_quick_chat(&self, quick_chat_buffer: &[u8]) -> Result<(), RLBotError> {
let status = (self.dll.send_quick_chat)(
quick_chat_buffer.as_ptr() as *mut c_void,
quick_chat_buffer.len() as c_int,
);
core_result(status)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn update_player_input(
&self,
player_input: ffi::PlayerInput,
player_index: c_int,
) -> Result<(), RLBotError> {
let status = (self.dll.update_player_input)(player_input, player_index);
core_result(status)
}
pub fn update_player_input_flatbuffer(
&self,
player_input_buffer: &[u8],
) -> Result<(), RLBotError> {
let status = (self.dll.update_player_input_flatbuffer)(
player_input_buffer.as_ptr() as *mut c_void,
player_input_buffer.len() as c_int,
);
core_result(status)
}
pub fn render_group(&self, render_group_buffer: &[u8]) -> Result<(), RLBotError> {
let status = (self.dll.render_group)(
render_group_buffer.as_ptr() as *mut c_void,
render_group_buffer.len() as c_int,
);
core_result(status)
}
pub fn get_ball_prediction<'fb>(&self) -> Option<flat::BallPrediction<'fb>> {
let byte_buffer = (self.dll.get_ball_prediction)();
get_flatbuffer::<flat::BallPrediction<'_>>(byte_buffer)
}
#[deprecated(
note = "the struct-based methods are deprecated; use the flatbuffer equivalents instead"
)]
pub fn get_ball_prediction_struct(
&self,
result: &mut ffi::BallPredictionPacket,
) -> Result<(), RLBotError> {
let status = (self.dll.get_ball_prediction_struct)(result);
core_result(status)
}
}
fn core_result(status: ffi::RLBotCoreStatus) -> Result<(), RLBotError> {
match status {
ffi::RLBotCoreStatus::Success => Ok(()),
_ => Err(RLBotError { status }),
}
}
fn get_flatbuffer<'a, T: flatbuffers::Follow<'a> + 'a>(
byte_buffer: ffi::ByteBuffer,
) -> Option<T::Inner> {
if byte_buffer.size == 0 {
return None;
}
let ptr = byte_buffer.ptr as *const u8;
let size = byte_buffer.size as usize;
let slice = unsafe { slice::from_raw_parts(ptr, size) };
Some(flatbuffers::get_root::<T>(slice))
}
#[cfg(test)]
mod tests {
use crate::{ffi, interface::RLBotInterface};
use std::{error::Error, mem};
#[test]
#[ignore = "compile-only test"]
fn game_data_is_send() -> Result<(), Box<dyn Error>> {
fn assert_send<T: Send + 'static>(_: T) {}
assert_send(ffi::LiveDataPacket::default());
assert_send(ffi::RigidBodyTick::default());
assert_send(ffi::FieldInfo::default());
assert_send(ffi::BallPredictionPacket::default());
let interface: RLBotInterface = unsafe { mem::uninitialized() };
assert_send(interface.update_live_data_packet_flatbuffer());
assert_send(interface.update_rigid_body_tick_flatbuffer());
assert_send(interface.update_field_info_flatbuffer());
assert_send(interface.get_ball_prediction());
Ok(())
}
}