diff --git a/Cargo.lock b/Cargo.lock index dcb675b..fab529a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2425,18 +2425,21 @@ dependencies = [ ] [[package]] -name = "oj_factory_api" +name = "oj_factory_web" version = "1.1.0" dependencies = [ + "actix-files", "actix-web", "base64", "clap", "env_logger", "git-version", + "handlebars", "libfj", "log", "oj_rc_core", "oj_rc_factory", + "serde", "serde_json", ] diff --git a/rc_core/src/cubes/connections.rs b/rc_core/src/cubes/connections.rs new file mode 100644 index 0000000..ee2c7f3 --- /dev/null +++ b/rc_core/src/cubes/connections.rs @@ -0,0 +1,387 @@ +pub const CUBE_CONNECTIONS: &[CubeConnections] = &[ + CubeConnections { + id: 606866102, // Protonium Clasp + connections: &[ + CubeConnection { + direction: (0, 0, 1), + position: (0, 38, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 48, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 58, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 68, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 78, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 88, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 98, 25), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 108, 25), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 38, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 48, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 58, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 68, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 78, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 88, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 98, -24), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 108, -24), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 38, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 48, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 58, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 68, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 78, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 88, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 98, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (25, 108, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 38, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 48, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 58, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 68, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 78, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 88, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 98, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-24, 108, 0), + }, + /*CubeConnection { // assumed by game client (but not useful) + direction: (0, -1, 0), + position: (0, 0, 0), + },*/ + ], + }, + CubeConnections { + id: 3950293873, // Protonium Crystal + connections: &[ + // -y (bottom) + CubeConnection { // assumed by game client + direction: (0, -1, 0), + position: (0, 0, 0), + }, + CubeConnection { + direction: (0, -1, 0), + position: (1, 0, 0), + }, + CubeConnection { + direction: (0, -1, 0), + position: (0, 0, 1), + }, + CubeConnection { + direction: (0, -1, 0), + position: (1, 0, 1), + }, + // +y (top) + CubeConnection { + direction: (0, 1, 0), + position: (0, 9, 0), + }, + CubeConnection { + direction: (0, 1, 0), + position: (1, 9, 0), + }, + CubeConnection { + direction: (0, 1, 0), + position: (0, 9, 1), + }, + CubeConnection { + direction: (0, 1, 0), + position: (1, 9, 1), + }, + // -x (right?) + CubeConnection { + direction: (1, 0, 0), + position: (5, 4, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (5, 4, 1), + }, + CubeConnection { + direction: (1, 0, 0), + position: (5, 5, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (5, 5, 1), + }, + // -x (left?) + CubeConnection { + direction: (-1, 0, 0), + position: (-4, 4, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-4, 4, 1), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-4, 5, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (-4, 5, 1), + }, + // +z (back) + CubeConnection { + direction: (0, 0, 1), + position: (0, 4, 5), + }, + CubeConnection { + direction: (0, 0, 1), + position: (1, 4, 5), + }, + CubeConnection { + direction: (0, 0, 1), + position: (0, 5, 5), + }, + CubeConnection { + direction: (0, 0, 1), + position: (1, 5, 5), + }, + // -z (front) + CubeConnection { + direction: (0, 0, -1), + position: (0, 4, -4), + }, + CubeConnection { + direction: (0, 0, -1), + position: (1, 4, -4), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 5, -4), + }, + CubeConnection { + direction: (0, 0, -1), + position: (1, 5, -4), + }, + // diagonal faces + CubeConnection { + direction: (-1, 0, 0), + position: (-2, 2, -2), + }, + CubeConnection { + direction: (0, -1, 0), + position: (-2, 2, -2), + }, + + CubeConnection { + direction: (1, 0, 0), + position: (3, 2, -2), + }, + CubeConnection { + direction: (0, -1, 0), + position: (3, 2, -2), + }, + CubeConnection { + direction: (0, 0, -1), + position: (3, 2, -2), + }, + + CubeConnection { + direction: (-1, 0, 0), + position: (-2, 2, 3), + }, + CubeConnection { + direction: (0, -1, 0), + position: (-2, 2, 3), + }, + CubeConnection { + direction: (0, 0, 1), + position: (-2, 2, 3), + }, + + CubeConnection { + direction: (1, 0, 0), + position: (3, 2, 3), + }, + CubeConnection { + direction: (0, -1, 0), + position: (3, 2, 3), + }, + CubeConnection { + direction: (0, 0, 1), + position: (3, 2, 3), + }, + + CubeConnection { + direction: (-1, 0, 0), + position: (-2, 6, -2), + }, + CubeConnection { + direction: (0, 1, 0), + position: (-2, 6, -2), + }, + CubeConnection { + direction: (0, 0, -1), + position: (-2, 6, -2), + }, + + CubeConnection { + direction: (1, 0, 0), + position: (3, 6, -2), + }, + CubeConnection { + direction: (0, 1, 0), + position: (3, 6, -2), + }, + CubeConnection { + direction: (0, 0, -1), + position: (3, 6, -2), + }, + + CubeConnection { + direction: (-1, 0, 0), + position: (-2, 6, 3), + }, + CubeConnection { + direction: (0, 1, 0), + position: (-2, 6, 3), + }, + CubeConnection { + direction: (0, 0, 1), + position: (-2, 6, 3), + }, + + CubeConnection { + direction: (1, 0, 0), + position: (3, 6, 3), + }, + CubeConnection { + direction: (0, 1, 0), + position: (3, 6, 3), + }, + CubeConnection { + direction: (0, 0, 1), + position: (3, 6, 3), + }, + ], + }, + CubeConnections { + id: 0, // (default) + connections: &[ + CubeConnection { + direction: (0, 0, 1), + position: (0, 0, 0), + }, + CubeConnection { + direction: (0, 1, 0), + position: (0, 0, 0), + }, + CubeConnection { + direction: (1, 0, 0), + position: (0, 0, 0), + }, + CubeConnection { + direction: (0, 0, -1), + position: (0, 0, 0), + }, + CubeConnection { + direction: (0, -1, 0), + position: (0, 0, 0), + }, + CubeConnection { + direction: (-1, 0, 0), + position: (0, 0, 0), + }, + ], + }, +]; + +#[derive(Copy, Clone)] +pub struct CubeConnections { + pub id: u32, + pub connections: &'static [CubeConnection], +} + +#[derive(Copy, Clone)] +pub struct CubeConnection { + pub direction: (i8, i8, i8), + pub position: (i8, i8, i8), +} diff --git a/rc_core/src/cubes/locations_of.rs b/rc_core/src/cubes/locations_of.rs index e032e69..42d9967 100644 --- a/rc_core/src/cubes/locations_of.rs +++ b/rc_core/src/cubes/locations_of.rs @@ -1,3 +1,6 @@ +const CRYSTAL_ID: u32 = 3950293873; +const CLASP_ID: u32 = 606866102; + pub struct CubeLocationsParser; pub struct CubeLocationInfo { @@ -68,6 +71,34 @@ impl CubeLocationsParser { .collect() } + fn locations_sorted_by_distance_from_point_reward_inlines(cubes: &[super::parser::Cube], point: (u8, u8, u8), locations_of_id: u32, inline_div: f32) -> Vec { + let target_x = point.0 as f32; + let target_y = point.1 as f32; + let target_z = point.2 as f32; + let mut relevant_cubes: Vec<(f32, CubeLocationInfo)> = cubes.iter() + .filter(|x| x.id == locations_of_id) + .map(|cube| { + let is_inline = cube.x.wrapping_sub(point.0) == 0 || cube.z.wrapping_sub(point.2) == 0; + let distance = ( + (cube.x as f32 - target_x).powi(2) + + (cube.y as f32 - target_y).powi(2) + + (cube.z as f32 - target_z).powi(2) + ).sqrt(); + let distance = if is_inline { distance / inline_div } else { distance }; + (distance, CubeLocationInfo { + x: cube.x, + y: cube.y, + z: cube.z, + extras: cube.orientation, + }) + }) + .collect(); + relevant_cubes.sort_by_key(|(distance, _)| (distance * 1_000_000.0) as i64); + relevant_cubes.into_iter() + .map(|(_, cube)| cube) + .collect() + } + pub fn locations_of_by_distance_to_first(&self, r: &mut dyn std::io::Read, locations_of_id: u32, distance_to_id: u32) -> Vec { match super::parser::Cube::parse_list(r) { Ok(cubes) => { @@ -113,4 +144,195 @@ impl CubeLocationsParser { } } } + + pub fn locations_of_by_distance_from_center(&self, r: &mut dyn std::io::Read, locations_of_id: u32) -> Vec { + match super::parser::Cube::parse_list(r) { + Ok(cubes) => { + let mut total = 0; + let mut total_x = 0; + let mut total_y = 0; + let mut total_z = 0; + for cube in cubes.iter() { + if cube.id == locations_of_id { + total += 1; + total_x += cube.x as usize; + total_y += cube.y as usize; + total_z += cube.z as usize; + } + } + let center = (total_x / total, total_y / total, total_z / total); + let center = (center.0 as u8, center.1 as u8, center.2 as u8); + Self::locations_sorted_by_distance_from_point_reward_inlines( + &cubes, + center, + locations_of_id, + 4.0, + ) + } + Err(e) => { + log::error!("Failed to parse cube data to find cube locations: {}", e); + Vec::default() + } + } + } + + pub fn locations_of_reactor_sort(&self, r: &mut dyn std::io::Read) -> Vec { + use super::{CUBE_CONNECTIONS, CUBE_ROTATIONS}; + match super::parser::Cube::parse_list(r) { + Ok(cubes) => { + // get connection data + let location_cube_connections = if let Some(conn) = CUBE_CONNECTIONS.iter().find(|x| x.id == CRYSTAL_ID) { + conn + } else { + CUBE_CONNECTIONS.iter().find(|x| x.id == 0).unwrap() + }; + let connected_to_connections = if let Some(conn) = CUBE_CONNECTIONS.iter().find(|x| x.id == CLASP_ID) { + conn + } else { + CUBE_CONNECTIONS.iter().find(|x| x.id == 0).unwrap() + }; + // calculate connect target connection points + let mut abs_connected_to = None; + let mut target_cube_loc = None; + for cube in cubes.iter() { + if cube.id == CLASP_ID { + let rot_index = cube.orientation & 0b01111111; + let rot = &CUBE_ROTATIONS[rot_index as usize]; + log::trace!("Calculating target connection points"); + abs_connected_to = Some(calculate_absolute_connections(connected_to_connections, rot, (cube.x, cube.y, cube.z))); + target_cube_loc = Some(CubeLocationInfo { + x: cube.x, + y: cube.y, + z: cube.z, + extras: cube.orientation, + }); + break; + } + } + let mut available_faces = if let Some(abs_connected_to) = abs_connected_to { + abs_connected_to + } else { + log::error!("Failed to find cube with id {} to calculate connections to", CLASP_ID); + return Vec::default(); + }; + let target_cube_loc = target_cube_loc.unwrap(); + // find cubes connected to target (or to another relevant cube connected to the target) + let mut to_be_sorted = std::collections::HashMap::new(); + for (i, cube) in cubes.iter().enumerate() { + if cube.id == CRYSTAL_ID { + let rot_index = cube.orientation & 0b01111111; + let rot = &CUBE_ROTATIONS[rot_index as usize]; + log::trace!("Calculating location {} connection points", i); + let calc_conns = calculate_absolute_connections(location_cube_connections, rot, (cube.x, cube.y, cube.z)); + to_be_sorted.insert(i, calc_conns); + } + } + let mut sorted = Vec::with_capacity(to_be_sorted.len() + 1); + sorted.push(target_cube_loc); + let mut iteration = 0; + let mut random = rand::rng(); + let mut to_be_released = Vec::new(); + while !to_be_sorted.is_empty() && iteration < 32 { + for (cube_i, calc_conns) in to_be_sorted.iter() { + let connection = is_sharing_connection(calc_conns, &available_faces) + .and_then(|(cube_face_i, face_available_i)| { + use rand::Rng; + if face_available_i < connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len() { + // prioritize finding all target connections first + Some((cube_face_i, face_available_i)) + } else if iteration < 3 || (face_available_i >= connected_to_connections.connections.len() && sorted.len() < connected_to_connections.connections.len()) { + let random_face = random.random_range(0..calc_conns.len()); + if cube_face_i >= random_face { + Some((cube_face_i, face_available_i)) + } else { + None + } + } else { + Some((cube_face_i, face_available_i)) + } + }); + if connection.is_some() { + to_be_released.push(*cube_i); + let cube = &cubes[*cube_i]; + sorted.push(CubeLocationInfo { + x: cube.x, + y: cube.y, + z: cube.z, + extras: cube.orientation, + }); + } + } + for to_release in to_be_released.iter() { + if let Some(mut new_faces) = to_be_sorted.remove(to_release) { + available_faces.append(&mut new_faces); + } + } + // guarantee this will not endlessly try to find just target connections + // (this moves on to considering already-connected locations_of_id cubes) + log::debug!("Cube connection iteration {} found {} new connections", iteration, to_be_released.len()); + to_be_released.clear(); + iteration += 1; + } + if to_be_sorted.is_empty() { + log::debug!("Solved cube connections order in {} iterations", iteration); + } else { + log::warn!("Failed to solve cube connections order after {} iterations (returning incomplete list)", iteration); + } + sorted + } + Err(e) => { + log::error!("Failed to parse cube data to find cube locations by connections: {}", e); + Vec::default() + } + } + } +} + +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +struct AbsoluteConnection { + direction: (i8, i8, i8), + position: (u8, u8, u8), +} + +fn calculate_absolute_connections(conns: &super::connections::CubeConnections, rot: &num_quaternion::Quaternion, pos: (u8, u8, u8)) -> Vec { + let unit_rot = rot.normalize().unwrap(); + let mut abs_conns = Vec::with_capacity(conns.connections.len()); + for conn in conns.connections.iter() { + let rotated_pos = unit_rot.rotate_vector([ + conn.position.0 as f32, + conn.position.1 as f32, + conn.position.2 as f32 + ]); + let rotated_dir = unit_rot.rotate_vector([ + conn.direction.0 as f32, + conn.direction.1 as f32, + conn.direction.2 as f32 + ]); + let new_conn = AbsoluteConnection { + direction: (rotated_dir[0] as i8, rotated_dir[1] as i8, rotated_dir[2] as i8), + position: ( + pos.0.saturating_add_signed(rotated_pos[0] as i8).saturating_add_signed(rotated_dir[0].clamp(0.0, 1.0) as i8), + pos.1.saturating_add_signed(rotated_pos[1] as i8).saturating_add_signed(rotated_dir[1].clamp(0.0, 1.0) as i8), + pos.2.saturating_add_signed(rotated_pos[2] as i8).saturating_add_signed(rotated_dir[2].clamp(0.0, 1.0) as i8), + ), + }; + log::trace!("absolute connection point {:?}", new_conn.position); + abs_conns.push(new_conn); + } + + abs_conns +} + +fn is_sharing_connection(a: &[AbsoluteConnection], b: &[AbsoluteConnection]) -> Option<(usize, usize)> { + for (i_a, conn_a) in a.iter().enumerate() { + for (i_b, conn_b) in b.iter().enumerate() { + if conn_b.position == conn_a.position + && conn_b.direction.0 == -conn_a.direction.0 + && conn_b.direction.1 == -conn_a.direction.1 + && conn_b.direction.2 == -conn_a.direction.2 { + return Some((i_a, i_b)); + } + } + } + None } diff --git a/rc_core/src/cubes/mod.rs b/rc_core/src/cubes/mod.rs index 6a3d8c7..24f9638 100644 --- a/rc_core/src/cubes/mod.rs +++ b/rc_core/src/cubes/mod.rs @@ -1,4 +1,4 @@ - mod parser; +mod parser; mod weapon_list; pub use weapon_list::WeaponListParser; @@ -12,6 +12,12 @@ pub use locations_of::{CubeLocationsParser, CubeLocationInfo}; mod offsetter; pub use offsetter::OffsetParser; +mod connections; +pub use connections::CUBE_CONNECTIONS; + +mod rotations; +pub use rotations::CUBE_ROTATIONS; + //pub mod prefabs; pub struct CubeParsers { diff --git a/rc_core/src/cubes/offsetter.rs b/rc_core/src/cubes/offsetter.rs index ded628e..91e0fce 100644 --- a/rc_core/src/cubes/offsetter.rs +++ b/rc_core/src/cubes/offsetter.rs @@ -12,15 +12,27 @@ impl OffsetParser { let colours = &mut colours[4..]; for cube in cubes.chunks_mut(8) { // bytes 4, 5, 6 are x, y, z (respectively) - cube[4] = (cube[4] as i16 + offset.0) as _; - cube[5] = (cube[5] as i16 + offset.1) as _; - cube[6] = (cube[6] as i16 + offset.2) as _; + cube[4] = (cube[4] as u16).saturating_add_signed(offset.0) as _; + cube[5] = (cube[5] as u16).saturating_add_signed(offset.1) as _; + cube[6] = (cube[6] as u16).saturating_add_signed(offset.2) as _; } for colour in colours.chunks_mut(4) { // last 3 bytes are x, y, z (respectively) - colour[1] = (colour[1] as i16 + offset.0) as _; - colour[2] = (colour[2] as i16 + offset.1) as _; - colour[3] = (colour[3] as i16 + offset.2) as _; + colour[1] = (colour[1] as u16).saturating_add_signed(offset.0) as _; + colour[2] = (colour[2] as u16).saturating_add_signed(offset.1) as _; + colour[3] = (colour[3] as u16).saturating_add_signed(offset.2) as _; + } + } + + pub fn offset_inplace_with_id(&self, cubes: &mut [u8], offset: (i8, i8, i8), target_id: u32) { + let cubes = &mut cubes[4..]; + for cube in cubes.chunks_mut(8) { + let id = u32::from_le_bytes([cube[0], cube[1], cube[2], cube[3]]); + if id != target_id { continue; } + // bytes 4, 5, 6 are x, y, z (respectively) + cube[4] = cube[4].saturating_add_signed(offset.0); + cube[5] = cube[5].saturating_add_signed(offset.1); + cube[6] = cube[6].saturating_add_signed(offset.2); } } } diff --git a/rc_core/src/cubes/rotations.rs b/rc_core/src/cubes/rotations.rs new file mode 100644 index 0000000..4bdfbbc --- /dev/null +++ b/rc_core/src/cubes/rotations.rs @@ -0,0 +1,27 @@ +#[allow(clippy::approx_constant)] +pub const CUBE_ROTATIONS: [num_quaternion::Quaternion; 24] = [ + num_quaternion::Quaternion::new(1.0, 0.0, 0.0, 0.0), + num_quaternion::Quaternion::new(0.7071068, 0.0, 0.0, 0.7071068), + num_quaternion::Quaternion::new(0.0, 0.0, 0.0, 1.0), + num_quaternion::Quaternion::new(-0.7071068, 0.0, 0.0, 0.7071068), + num_quaternion::Quaternion::new(0.7071068, 0.0, 0.7071068, 0.0), + num_quaternion::Quaternion::new(0.5, 0.5, 0.5, 0.5), + num_quaternion::Quaternion::new(0.5, -0.5, -0.5, -0.5), + num_quaternion::Quaternion::new(-0.5, 0.5, -0.5, 0.5), + num_quaternion::Quaternion::new(-0.5, 0.5, 0.5, -0.5), + num_quaternion::Quaternion::new(0.5, 0.5, -0.5, -0.5), + num_quaternion::Quaternion::new(0.5, 0.5, -0.5, 0.5), + num_quaternion::Quaternion::new(-0.5, -0.5, -0.5, 0.5), + num_quaternion::Quaternion::new(-0.5, 0.5, -0.5, -0.5), + num_quaternion::Quaternion::new(0.0, 0.7071068, 0.0, 0.7071068), + num_quaternion::Quaternion::new(0.0, 0.0, 1.0, 0.0), + num_quaternion::Quaternion::new(0.0, 0.7071068, 0.7071068, 0.0), + num_quaternion::Quaternion::new(0.0, 1.0, 0.0, 0.0), + num_quaternion::Quaternion::new(0.0, 0.7071068, -0.7071068, 0.0), + num_quaternion::Quaternion::new(-0.7071068, 0.0, 0.7071068, 0.0), + num_quaternion::Quaternion::new(0.0, 0.7071068, 0.0, -0.7071068), + num_quaternion::Quaternion::new(0.7071068, 0.7071068, 0.0, 0.0), + num_quaternion::Quaternion::new(0.0, 0.0, -0.7071068, 0.7071068), + num_quaternion::Quaternion::new(-0.7071068, 0.7071068, 0.0, 0.0), + num_quaternion::Quaternion::new(0.0, 0.0, -0.7071068, -0.7071068), +]; diff --git a/rc_core/src/persist/multiplayer.rs b/rc_core/src/persist/multiplayer.rs index df77421..e671674 100644 --- a/rc_core/src/persist/multiplayer.rs +++ b/rc_core/src/persist/multiplayer.rs @@ -89,7 +89,7 @@ pub(super) fn default_net_conf() -> NetworkConf { resend_delay_base: 0.1, resend_delay_rtt_mult: 0.5, network_peer_update_interval: 1, - max_delay_for_disconnect_ms: 1000, + max_delay_for_disconnect_ms: 5000, } } @@ -117,7 +117,7 @@ pub(super) fn default_fake_users() -> Vec { }, implementation: ClientEmulation::Experimental, },*/ - FakePlayerConf { + /*FakePlayerConf { team: None, vehicle: super::garage::PrefabVehicle { name: Some("fake1".to_owned()), @@ -140,7 +140,7 @@ pub(super) fn default_fake_users() -> Vec { }, }, implementation: ClientEmulation::ClientAI, - }, + },*/ /*FakePlayerConf { team: None, vehicle: super::garage::PrefabVehicle { @@ -169,7 +169,56 @@ pub(super) fn default_fake_users() -> Vec { } pub(super) fn default_filler_users() -> Vec { - default_fake_users() + vec![ + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake1".to_owned()), + username: "ServerFiller1".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake2".to_owned()), + username: "ServerFiller2".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake3".to_owned()), + username: "ServerFiller3".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, + FakePlayerConf { + team: None, + vehicle: super::garage::PrefabVehicle { + name: Some("fake4".to_owned()), + username: "ServerFiller4".to_owned(), + id: super::garage::PrefabId::Raw { + cube_data: Vec::from(crate::persist::VALID_ROBOT), + colour_data: Vec::from(crate::persist::VALID_COLOUR), + }, + }, + implementation: ClientEmulation::ClientAI, + }, + ] } #[derive(Serialize, Deserialize, Clone, Debug)] @@ -235,13 +284,14 @@ fn default_equalizer() -> super::garage::PrefabVehicle { } fn default_ba_base() -> super::garage::PrefabVehicle { + let mut cube_data = vec![ + 0x84, 0x01, 0x00, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x24, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x48, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x43, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x2A, 0x1A, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x61, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3A, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3E, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x53, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x51, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x58, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x61, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x44, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x25, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x43, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x6B, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x57, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x57, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x61, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x2F, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x57, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x3F, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x39, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x57, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x2A, 0x47, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x57, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x5C, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x2A, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x61, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x39, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x57, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x2F, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x48, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x66, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x43, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2A, 0x1F, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x25, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x4D, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x62, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x20, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x66, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x2A, 0x42, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x2F, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x66, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x48, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x2A, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x5C, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x5C, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x43, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x48, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2F, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x2F, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x35, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x4E, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x3F, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x4D, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x3E, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x49, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x6B, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x6B, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x6B, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x49, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x53, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x43, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x4D, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x6B, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x25, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x52, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x5D, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x34, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x3E, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x4D, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x44, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x4D, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x67, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x61, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x34, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x25, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x52, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4D, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x57, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x5C, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x66, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2F, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x39, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x2A, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x25, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x52, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x4D, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x52, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x61, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x2A, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x6B, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x2B, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x52, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x61, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x25, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x6B, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x2A, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x34, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x57, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x2F, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2A, 0x11, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x49, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x34, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x48, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x66, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x5C, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x39, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x53, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x4D, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x43, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2F, 0x29, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x34, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2A, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x5C, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x61, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x25, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x3E, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2A, 0x2F, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x57, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x39, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x25, 0x16, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x44, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x6B, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x25, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x34, 0x2A, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x39, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x61, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x58, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x67, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x34, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x61, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x43, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2F, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x67, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x2A, 0x47, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x43, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x2A, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x6B, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x4D, 0x42, 0x06, 0xB6, 0x0A, 0x2C, 0x24, 0x2C, 0x00, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x62, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x4D, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x57, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x61, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x6B, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x2A, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x30, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x34, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x39, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x66, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x66, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x35, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x2A, 0x1B, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x2A, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x3F, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x62, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x2A, 0x4C, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x52, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x48, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x35, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3E, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x34, 0x2F, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x2A, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x6B, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x5D, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x66, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x43, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x2B, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x57, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x57, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x3E, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x6B, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3A, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x39, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x2F, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x3A, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x52, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x5D, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x66, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x61, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x4D, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x6B, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x61, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x4D, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2B, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x2A, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x39, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x58, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2A, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x43, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x25, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x2A, 0x43, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x57, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x4E, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x43, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x48, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x39, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2F, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x4E, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x25, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2F, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x3E, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x39, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x4D, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x39, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x39, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x25, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x5C, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x43, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x43, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x2F, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x66, 0x51, 0x06, ]; + crate::cubes::OffsetParser.offset_inplace_with_id(&mut cube_data, (0, 10, 0), 3950293873); super::garage::PrefabVehicle { name: Some("Prefab team base".to_owned()), username: "server".to_owned(), id: super::garage::PrefabId::Raw { - cube_data: vec![ - 0x84, 0x01, 0x00, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x24, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x67, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x48, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x43, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x2A, 0x1A, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x61, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3A, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3E, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x53, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x51, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x58, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x61, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x44, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x25, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x43, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x6B, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x57, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x57, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x61, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x2F, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x57, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x3F, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x39, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x57, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x2A, 0x47, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x57, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x5C, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x2A, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x61, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x39, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x57, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x2F, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x48, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x66, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x43, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2A, 0x1F, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x25, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x4D, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x62, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x20, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x66, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x2A, 0x42, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x2F, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x66, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x48, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x2A, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x5C, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x5C, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x43, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x48, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2F, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x2F, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x35, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x4E, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x3F, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x4D, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x3E, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x49, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x6B, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x6B, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x6B, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x49, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x53, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x43, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x4D, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x6B, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x25, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x34, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x52, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x5D, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x34, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x3E, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x4D, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x44, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x4D, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x67, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x61, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x34, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x25, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x52, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4D, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x57, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x5C, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x66, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2F, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x39, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x2A, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x44, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x25, 0x34, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x52, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x4D, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x52, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x61, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x2A, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x6B, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x2B, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x52, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x39, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x61, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x25, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x6B, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x2A, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x34, 0x4D, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x6B, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x57, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x2F, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2A, 0x11, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x49, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x34, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x48, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x66, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x5C, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x39, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x53, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x4D, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x43, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2F, 0x29, 0x02, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x34, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x61, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2A, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x5C, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x61, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x25, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x3E, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2A, 0x2F, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x57, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x39, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x57, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x25, 0x16, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x44, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x6B, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x25, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x34, 0x2A, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x39, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x61, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x58, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x67, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x34, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x61, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x43, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x2F, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x67, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x41, 0x2A, 0x47, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x3E, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x43, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x2A, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x62, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x6B, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x4D, 0x42, 0x06, 0xB6, 0x0A, 0x2C, 0x24, 0x2C, 0x00, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x62, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x4D, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x57, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x61, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x6B, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x2A, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x30, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x33, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x34, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x39, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x66, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x66, 0x3D, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x34, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x35, 0x38, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x2A, 0x1B, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x48, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x2A, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x4D, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x3F, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x62, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x2A, 0x4C, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x44, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x52, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x48, 0x1A, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x35, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3E, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x34, 0x2F, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x2A, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x6B, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x5D, 0x42, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x3D, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x66, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x27, 0x43, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x5C, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x2B, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x66, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x57, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x5C, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x57, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x3E, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x3E, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x28, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x6B, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x30, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x43, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x3A, 0x29, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x2A, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x39, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x2F, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x57, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x3A, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x25, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x43, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x52, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x30, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x5C, 0x2E, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4B, 0x25, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x40, 0x5D, 0x1A, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x3A, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x52, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x66, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x61, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x4D, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x6B, 0x48, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x61, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x4D, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x2F, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2B, 0x2E, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x2A, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x39, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x48, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x58, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0A, 0x2A, 0x39, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x62, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x46, 0x43, 0x42, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x25, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x2A, 0x43, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x57, 0x4D, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x4E, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x09, 0x4E, 0x33, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x43, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x19, 0x48, 0x15, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x39, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x2F, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x24, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x4E, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0E, 0x25, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x34, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3C, 0x2F, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x3E, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x3E, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x52, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x14, 0x39, 0x1A, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x4D, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x13, 0x39, 0x2F, 0x0C, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x39, 0x47, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x3A, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x52, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x4E, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x25, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x58, 0x1F, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x45, 0x44, 0x15, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x1D, 0x5C, 0x10, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x48, 0x51, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x4F, 0x66, 0x38, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x39, 0x3D, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x0F, 0x43, 0x3E, 0x17, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x61, 0x1F, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x37, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x43, 0x4C, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x3B, 0x58, 0x47, 0x00, 0x71, 0xB3, 0x74, 0xEB, 0x32, 0x2F, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x2D, 0x2A, 0x0B, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x1E, 0x25, 0x10, 0x06, 0x71, 0xB3, 0x74, 0xEB, 0x18, 0x2F, 0x15, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x4A, 0x4D, 0x29, 0x16, 0x71, 0xB3, 0x74, 0xEB, 0x23, 0x66, 0x51, 0x06, - ], + cube_data, colour_data: vec![0, 0, 0, 0], // ignored } } diff --git a/rc_multiplayer/src/matches/aggregate.rs b/rc_multiplayer/src/matches/aggregate.rs index 2fec6e8..8f0a607 100644 --- a/rc_multiplayer/src/matches/aggregate.rs +++ b/rc_multiplayer/src/matches/aggregate.rs @@ -5,6 +5,7 @@ pub struct GameMatches { map_configs: std::collections::HashMap, //fake_players: Vec, cube_parsers: std::sync::Arc, + ba_sorted_crystals: tokio::sync::RwLock>>, // cached after first calculation ba_settings: std::sync::Arc, pit_settings: std::sync::Arc, tdm_settings: std::sync::Arc, @@ -23,6 +24,7 @@ impl GameMatches { .collect(), //fake_players: >::fake_players(conf), cube_parsers, + ba_sorted_crystals: tokio::sync::RwLock::new(std::sync::Arc::new(Vec::default())), ba_settings: std::sync::Arc::new(>::ba_settings(conf)), pit_settings: std::sync::Arc::new(>::pit_settings(conf)), tdm_settings: std::sync::Arc::new(>::tdm_settings(conf)), @@ -110,7 +112,17 @@ impl GameMatches { code: oj_rc_core::persist::user::MultiplayerErrorCode::CustomString, message: e.error_msg().map(|x| x.to_owned()).unwrap_or_else(|| "Failed to resolve special settings for Battle Arena".to_owned()), })?; - let inner = super::modes::BattleArenaLogic::new(&self.mode_configs.battle_arena, &map_config, &self.cube_parsers, &players, resolved_ba_conf); + let crystals = if self.ba_sorted_crystals.read().await.is_empty() { + let crystals = std::sync::Arc::new( + self.cube_parsers.locations_of() + .locations_of_reactor_sort(&mut std::io::Cursor::new(&resolved_ba_conf.base_machine_map)) + ); + *self.ba_sorted_crystals.write().await = crystals.clone(); + crystals + } else { + self.ba_sorted_crystals.read().await.clone() + }; + let inner = super::modes::BattleArenaLogic::new(&self.mode_configs.battle_arena, &map_config, &players, resolved_ba_conf, crystals); let engine = super::GenericGamemodeEngine::new( game_info, map_config, diff --git a/rc_multiplayer/src/matches/modes/battle_arena.rs b/rc_multiplayer/src/matches/modes/battle_arena.rs index 6c59e57..6441a22 100644 --- a/rc_multiplayer/src/matches/modes/battle_arena.rs +++ b/rc_multiplayer/src/matches/modes/battle_arena.rs @@ -589,17 +589,17 @@ impl EqualizerTracker { } } - async fn damage_equalizer(&self, damage: i32, generic: &crate::matches::GenericGamemodeEngine, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData, bases: &std::collections::HashMap, crystals: &[oj_rc_core::cubes::CubeLocationInfo]) { + async fn damage_equalizer(&self, damage: i32, generic: &crate::matches::GenericGamemodeEngine, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData, bases: &std::collections::HashMap, crystals: &[oj_rc_core::cubes::CubeLocationInfo], crystal_health: u32) { if !self.activated.load(std::sync::atomic::Ordering::Relaxed) { return; } let damage_u64 = damage as u64; let old_health = self.health.fetch_sub(damage as u64, std::sync::atomic::Ordering::Relaxed); if old_health <= damage_u64 { // equalizer is now destroyed - self.destroy_equalizer(generic, ba_config, bases, crystals).await; + self.destroy_equalizer(generic, ba_config, bases, crystals, crystal_health).await; } } - async fn destroy_equalizer(&self, generic: &crate::matches::GenericGamemodeEngine, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData, bases: &std::collections::HashMap, crystals: &[oj_rc_core::cubes::CubeLocationInfo]) { + async fn destroy_equalizer(&self, generic: &crate::matches::GenericGamemodeEngine, ba_config: &oj_rc_core::data::battle_arena_config::BattleArenaData, bases: &std::collections::HashMap, crystals: &[oj_rc_core::cubes::CubeLocationInfo], crystal_health: u32) { if !self.activated.swap(false, std::sync::atomic::Ordering::Relaxed) { return; } self.cancelled.store(true, std::sync::atomic::Ordering::Relaxed); let eq_start = self.start.load(std::sync::atomic::Ordering::Relaxed); @@ -615,7 +615,7 @@ impl EqualizerTracker { losing_base.cube_index.store(winning_base.cube_index.load(std::sync::atomic::Ordering::Relaxed), std::sync::atomic::Ordering::Relaxed); let new_index = losing_base.max_index(); for i in old_index..new_index { - losing_base.crystals_healths[i].store(u8::MAX, std::sync::atomic::Ordering::Relaxed); + losing_base.crystals_healths[i].store(crystal_health, std::sync::atomic::Ordering::Relaxed); } let base_heal = losing_base.generate_full_base_heal(losing_team, ba_config.protonium_health as u32, crystals); generic.broadcast( @@ -739,7 +739,7 @@ impl BaseTracker { //let base = self.bases.get(&base_id).unwrap(); let target_crystals = &crystals[old_index..new_index]; for crystal_i in old_index..new_index { - base.crystals_healths[crystal_i].store(u8::MAX, std::sync::atomic::Ordering::Relaxed); + base.crystals_healths[crystal_i].store(crystal_health, std::sync::atomic::Ordering::Relaxed); } rlnl::events::HealedCubes { healed_machine: base_id as u16, @@ -748,9 +748,12 @@ impl BaseTracker { num_healed_cubes: target_crystals.len() as _, hit_cubes: target_crystals .iter() - .map(|loc| rlnl::types::HitCubeInfo { - pos: rlnl::types::Byte3 { x: loc.x, y: loc.y, z: loc.z, }, - damage: crystal_health as i32, + .map(|loc| { + log::trace!("Healing base cube at grid ({}, {}, {})", loc.x, loc.y, loc.z); + rlnl::types::HitCubeInfo { + pos: rlnl::types::Byte3 { x: loc.x, y: loc.y, z: loc.z, }, + damage: crystal_health as i32, + } }) .collect(), } @@ -787,21 +790,23 @@ impl BaseTracker { * ((PointTracker::TICK_MS as f32) / (generic.game_duration.as_millis() as f32)) * ((self.bases.len() as f32) / (capture_points_count as f32)); let increment = tick_info.delta as f32 * (*owned_points as f32) * one_tick * multiplier; + #[cfg(debug_assertions)] + let increment = increment + 0.1; let old_float_index = tracked_base.cube_index.fetch_add(increment, std::sync::atomic::Ordering::SeqCst); let new_float_index = old_float_index + increment; let old_index = (old_float_index.ceil() as usize).clamp(0, crystals.len()); let new_index = (new_float_index.ceil() as usize).clamp(0, crystals.len()); if new_index != old_index { - log::debug!("Base {} increment passed a crystal index barrier", base_id); + log::trace!("Base {} increment passed a crystal index barrier", base_id); let first_damaged = tracked_base.first_damaged(old_index, crystal_health); let payload = if new_index - old_index == 1 && first_damaged.is_some() { // undo cube_index update tracked_base.cube_index.fetch_sub(increment, std::sync::atomic::Ordering::SeqCst); - log::debug!("Skipping increment in favour of healing damaged/destroyed cube"); + log::trace!("Skipping increment in favour of healing damaged/destroyed cube"); #[allow(clippy::unnecessary_unwrap)] // have you seen the mess this would be with another if statement? let first_damaged = first_damaged.unwrap(); - let healing = crystal_health - tracked_base.calculate_crystal_health(first_damaged, crystal_health); - tracked_base.crystals_healths[first_damaged].store(u8::MAX, std::sync::atomic::Ordering::Relaxed); + //let healing = crystal_health - tracked_base.calculate_crystal_health(first_damaged, crystal_health); + tracked_base.crystals_healths[first_damaged].store(crystal_health, std::sync::atomic::Ordering::Relaxed); let target_crystal = &crystals[first_damaged]; rlnl::events::HealedCubes { healed_machine: *base_id as u16, @@ -811,7 +816,8 @@ impl BaseTracker { hit_cubes: vec![ rlnl::types::HitCubeInfo { pos: rlnl::types::Byte3 { x: target_crystal.x, y: target_crystal.y, z: target_crystal.z, }, - damage: healing as i32, + //damage: healing as i32, + damage: crystal_health.saturating_sub(2) as i32, } ], } @@ -843,6 +849,14 @@ impl BaseTracker { true ).await; + let charge_ratio = (new_index as f64) / (crystals.len() as f64); + let old_charge_ratio = (old_index as f64) / (crystals.len() as f64); + let charge_percent = (charge_ratio * 100.0) as usize; + let old_charge_percent = (old_charge_ratio * 100.0) as usize; + if charge_percent != old_charge_percent && charge_percent.is_multiple_of(10) { + log::debug!("Base {} is charged to {}% ({}/{}) in game {}", base_id, charge_percent, new_index, crystals.len(), generic.game_guid()); + } + if new_index == crystals.len() { // team base is charged to 100% //self.do_win(*base_id, WinMode::BaseFull, generic).await; @@ -862,7 +876,7 @@ impl BaseTracker { struct BaseInfo { cube_index: atomic_float::AtomicF32, - crystals_healths: Vec, + crystals_healths: Vec, } impl BaseInfo { @@ -870,15 +884,14 @@ impl BaseInfo { Self { cube_index: atomic_float::AtomicF32::new(0.0), crystals_healths: (0..crystals.len()) - .map(|_| std::sync::atomic::AtomicU8::new(0)) + .map(|_| std::sync::atomic::AtomicU32::new(0)) .collect() } } #[inline] - fn calculate_crystal_health(&self, i: usize, max_health: u32) -> u32 { - (((self.crystals_healths[i].load(std::sync::atomic::Ordering::Relaxed) as f32) / (u8::MAX as f32)) - * (max_health as f32)).ceil() as u32 + fn calculate_crystal_health(&self, i: usize) -> u32 { + self.crystals_healths[i].load(std::sync::atomic::Ordering::Relaxed) } #[inline] @@ -898,7 +911,7 @@ impl BaseInfo { fn first_damaged(&self, old_index: usize, max_health: u32) -> Option { for i in 0..old_index { - let health = self.calculate_crystal_health(i, max_health); + let health = self.calculate_crystal_health(i); if health != 0 && health != max_health { return Some(i); } @@ -907,27 +920,27 @@ impl BaseInfo { } /// returns whether crystal exists - fn damage_crystal_at_pos(&self, pos: rlnl::types::Byte3, damage: i32, crystals: &[oj_rc_core::cubes::CubeLocationInfo], max_health: u32) -> bool { + fn damage_crystal_at_pos(&self, pos: rlnl::types::Byte3, damage: i32, crystals: &[oj_rc_core::cubes::CubeLocationInfo]) -> Option { if let Some((index, _)) = crystals.iter().enumerate().find(|(_i, crystal)| crystal.x == pos.x && crystal.y == pos.y && crystal.z == pos.z) { let max_index = self.max_index(); - if index > max_index { return false; } - self.damage_crystal(index, damage, max_health); - true + if index > max_index { return None; } + self.damage_crystal(index, damage); + Some(index) } else { - false + None } } /// returns whether crystal was destroyed - fn damage_crystal(&self, i: usize, damage: i32, max_health: u32) -> bool { - let damage_byte = (((damage as f32) / (max_health as f32)) * (u8::MAX as f32)).ceil() as u8; - let old_health = self.crystals_healths[i].fetch_sub(damage_byte, std::sync::atomic::Ordering::Relaxed); - log::debug!("Crystal {} damaged (was {}, now {}, delta {})", i, old_health, old_health.saturating_sub(damage_byte), damage_byte); - if old_health < damage_byte { + fn damage_crystal(&self, i: usize, damage: i32) -> bool { + let damage = damage as u32; + let old_health = self.crystals_healths[i].fetch_sub(damage, std::sync::atomic::Ordering::Relaxed); + log::info!("Crystal {} damaged (was {}, now {}, delta {})", i, old_health, old_health.saturating_sub(damage), damage); + if damage > old_health { // guarantee underflow behaviour self.crystals_healths[i].store(0, std::sync::atomic::Ordering::Relaxed); } - old_health != 0 && old_health >= damage_byte + old_health != 0 && damage >= old_health } /// returns whether crystal exists @@ -950,7 +963,7 @@ impl BaseInfo { let max_index = self.max_index(); let target_crystals: Vec = (0..crystals.len()) .take_while(|&i| i <= max_index) - .filter(|&i| self.calculate_crystal_health(i, max_health) != 0) + .filter(|&i| self.calculate_crystal_health(i) != 0) .map(|i| { let target_loc = &crystals[i]; rlnl::types::HitCubeInfo { @@ -985,18 +998,14 @@ pub struct BattleArenaLogic { base_tracking: BaseTracker, surrender_tracking: super::trackers::SurrenderGameTracker, //cube_parser: std::sync::Arc, - crystals: Vec, + crystals: std::sync::Arc>, config: oj_rc_core::data::battle_arena_config::BattleArenaData, } impl BattleArenaLogic { - const CRYSTAL_ID: u32 = 3950293873; - const CLASP_ID: u32 = 606866102; - - pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, map: &oj_rc_core::persist::config::MapConfig, parsers: &oj_rc_core::cubes::CubeParsers, players: &[oj_rc_core::persist::user::PlayerDescriptor], ba_config: oj_rc_core::data::battle_arena_config::BattleArenaData) -> Self { - let cube_parser = parsers.locations_of(); - let crystals = cube_parser.locations_of_by_distance_to_first(&mut std::io::Cursor::new(&ba_config.base_machine_map), Self::CRYSTAL_ID, Self::CLASP_ID); - //let crystals = cube_parser.locations_of_by_distance_from(&mut std::io::Cursor::new(&ba_config.base_machine_map), Self::CRYSTAL_ID, (44, 255, 46)); + pub fn new(config: &oj_rc_core::data::game_mode::GameModeConfig, map: &oj_rc_core::persist::config::MapConfig, players: &[oj_rc_core::persist::user::PlayerDescriptor], ba_config: oj_rc_core::data::battle_arena_config::BattleArenaData, crystals: std::sync::Arc>) -> Self { + //let min_y = crystals.iter().min_by_key(|x| x.y).unwrap(); + //log::warn!("First crystal is as ({}, {}, {})", min_y.x, min_y.y, min_y.z); Self { respawn_full_heal_duration: config.respawn_full_heal_duration, respawn_heal_duration: config.respawn_heal_duration, @@ -1170,50 +1179,38 @@ impl BattleArenaLogic { } } - async fn do_team_base_stealing(&self, cube_damage: &rlnl::events::ingame::DestroyCubeNoEffect, generic: &crate::matches::GenericGamemodeEngine, _actual_damage_data: impl FnOnce(Vec) -> crate::matches::RlnlPacket) { + async fn do_team_base_stealing(&self, cube_damage: &rlnl::events::ingame::DestroyCubeNoEffect, generic: &crate::matches::GenericGamemodeEngine, actual_damage_data: impl FnOnce(Vec) -> crate::matches::RlnlPacket) { let base_id = cube_damage.hit_machine_id as u8; let mut total_destroyed = 0; - let mut valid_cubes = Vec::with_capacity(cube_damage.hit_cubes.len()); + let mut total_damaged = 0; + let mut actual_cube_damage = Vec::with_capacity(cube_damage.hit_cubes.len()); if let Some(base) = self.base_tracking.bases.get(&base_id) { for hit_cube in cube_damage.hit_cubes.iter() { if let Some(damage) = hit_cube.status.damage { - if base.damage_crystal_at_pos(hit_cube.loc, damage, &self.crystals, self.config.protonium_health as u32) { - valid_cubes.push(hit_cube.to_owned()); + if base.damage_crystal_at_pos(hit_cube.loc, damage, &self.crystals).is_some() { + actual_cube_damage.push(hit_cube.to_owned()); + total_damaged += 1; + } else { + log::warn!("Could not damage cube with damage status"); } } else if matches!(hit_cube.status.ty, rlnl::types::CubeHistoryEventType::Destroy) { if base.destroy_crystal_at_pos(hit_cube.loc, &self.crystals) { - valid_cubes.push(hit_cube.to_owned()); + // TODO handle cube graph disconnects + actual_cube_damage.push(hit_cube.to_owned()); total_destroyed += 1; } else { - log::warn!("Did not destroy cube with destroy status"); + log::warn!("Could not destroy cube with destroy status"); } } } - /*generic.broadcast( - rlnl::event_code::NetworkEvent::DestroyCubeNoEffect, - literustlib::packet::Property::ReliableOrdered, - &rlnl::events::ingame::DestroyCubeNoEffect { - shooting_machine_id: cube_damage.shooting_machine_id, - hit_machine_id: cube_damage.hit_machine_id, - target_type: rlnl::types::TargetType::TeamBase, - num_hits: valid_cubes.len() as _, - hit_cubes: valid_cubes, - }, - true, - ).await;*/ - //let actual_damage_data = actual_damage_data(valid_cubes); - /*generic.broadcast( + log::debug!("Destroyed {} ({} damaged) base cubes; {}/{} valid", total_destroyed, total_damaged, actual_cube_damage.len(), cube_damage.hit_cubes.len()); + let actual_damage_data = actual_damage_data(actual_cube_damage); + generic.broadcast( actual_damage_data.event, actual_damage_data.property, actual_damage_data.data.as_ref(), true, - ).await;*/ - /*generic.broadcast( - rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, - literustlib::packet::Property::ReliableOrdered, - &base.generate_full_base_heal(base_id, self.config.protonium_health as u32, &self.crystals), - true, - ).await;*/ + ).await; } if total_destroyed != 0 { if let Some(team_id) = self.player_tracking.team(cube_damage.shooting_machine_id as u8).await { @@ -1232,12 +1229,6 @@ impl BattleArenaLogic { old_index, new_index, ); - /*generic.broadcast( - rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, - literustlib::packet::Property::ReliableOrdered, - &base.generate_full_base_heal(team_id, self.config.protonium_health as u32, &self.crystals), - true, - ).await;*/ generic.broadcast( rlnl::event_code::NetworkEvent::SyncTeamBaseCubes, @@ -1253,11 +1244,12 @@ impl BattleArenaLogic { } async fn do_equalizer_damage(&self, cube_damage: &rlnl::events::ingame::DestroyCubeNoEffect, generic: &crate::matches::GenericGamemodeEngine) { + let crystal_health = self.config.protonium_health as u32; for hit_cube in cube_damage.hit_cubes.iter() { if let Some(damage) = hit_cube.status.damage { - self.base_tracking.equalizer.damage_equalizer(damage, generic, &self.config, &self.base_tracking.bases, &self.crystals).await; + self.base_tracking.equalizer.damage_equalizer(damage, generic, &self.config, &self.base_tracking.bases, &self.crystals, crystal_health).await; } else if matches!(hit_cube.status.ty, rlnl::types::CubeHistoryEventType::Destroy) { - self.base_tracking.equalizer.destroy_equalizer(generic, &self.config, &self.base_tracking.bases, &self.crystals).await; + self.base_tracking.equalizer.destroy_equalizer(generic, &self.config, &self.base_tracking.bases, &self.crystals, crystal_health).await; } } } @@ -1512,7 +1504,7 @@ impl CustomGameLogic for BattleArenaLogic { } }; self.do_team_base_stealing(&pseudo, generic, actual_damage_data).await; - true + false }, rlnl::types::TargetType::EqualizerCrystal => { self.do_equalizer_damage(&pseudo, generic).await; @@ -1543,8 +1535,8 @@ impl CustomGameLogic for BattleArenaLogic { data: Box::new(cube_dmg.to_owned()), } }; - self.do_team_base_stealing(cube_damage, generic, &actual_damage_data).await; - true + self.do_team_base_stealing(cube_damage, generic, actual_damage_data).await; + false }, rlnl::types::TargetType::EqualizerCrystal => { self.do_equalizer_damage(cube_damage, generic).await; diff --git a/rc_services_room/src/operations/battle_arena_config.rs b/rc_services_room/src/operations/battle_arena_config.rs index d94b86b..a29df26 100644 --- a/rc_services_room/src/operations/battle_arena_config.rs +++ b/rc_services_room/src/operations/battle_arena_config.rs @@ -19,6 +19,7 @@ impl SimpleOperation for BattleArenaConfigurer { async fn handle(&self, params: ParameterTable, user: &Self::User) -> Result, SimpleOpError> { let user_info = user.user()?; + log::warn!("Retrieved ba config"); let data = self.ba_conf.resolve_typed(user_info.as_ref().as_ref(), self.factory.as_ref(), &self.weapon_list, &self.cpu_counter).await?; let mut params = params.to_dict(); params.insert(PARAM_KEY, data);