An unofficial collection of APIs used in FreeJam games and mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
5.6KB

  1. use base64::{decode_config_buf, STANDARD};
  2. use std::io::Read;
  3. // TODO(maybe) parse iteratively instead of one-shot
  4. #[derive(Clone)]
  5. pub struct Cubes {
  6. pub provided_len: u32,
  7. cubes: Vec<Cube>,
  8. }
  9. impl Cubes {
  10. pub fn parse(cube_data: &mut Vec<u8>, colour_data: &mut Vec<u8>) -> Result<Self, ()> {
  11. // read first 4 bytes (cube count) from both arrays and make sure they match
  12. let mut cube_buf = [0; 4];
  13. let mut colour_buf = [0; 4];
  14. let mut cube_slice = cube_data.as_slice();
  15. let mut colour_slice = colour_data.as_slice();
  16. if let Ok(len) = cube_slice.read(&mut cube_buf) {
  17. if len != 4 {
  18. //println!("Failed reading cube_data len");
  19. return Err(());
  20. }
  21. } else {
  22. //println!("Failed to read cube_data");
  23. return Err(());
  24. }
  25. if let Ok(len) = colour_slice.read(&mut colour_buf) {
  26. if len != 4 {
  27. //println!("Failed reading colour_data len");
  28. return Err(());
  29. }
  30. } else {
  31. //println!("Failed to read colour_data");
  32. return Err(());
  33. }
  34. if !(cube_buf[0] == colour_buf[0]
  35. && cube_buf[1] == colour_buf[1]
  36. && cube_buf[2] == colour_buf[2]
  37. && cube_buf[3] == colour_buf[3]) {
  38. //println!("Values do not match");
  39. return Err(());
  40. }
  41. let mut cube_i = 4;
  42. let mut colour_i = 4;
  43. let mut parsed_cubes = Vec::with_capacity(cube_data.len() / 8);
  44. while cube_i < cube_data.len() && colour_i < colour_data.len() {
  45. let mut new_cube = Cube::default();
  46. if let Ok(cube_add) = new_cube.parse_cube_data(&mut cube_slice) {
  47. if let Ok(colour_add) = new_cube.parse_colour_data(&mut colour_slice) {
  48. cube_i += cube_add;
  49. colour_i += colour_add;
  50. parsed_cubes.push(new_cube);
  51. } else {
  52. // colour_data read error
  53. return Err(());
  54. }
  55. } else {
  56. // cube_data read error
  57. return Err(());
  58. }
  59. }
  60. Ok(Self {
  61. provided_len: u32::from_le_bytes(cube_buf),
  62. cubes: parsed_cubes,
  63. })
  64. }
  65. pub fn dump(&self) -> (Vec<u8>, Vec<u8>) {
  66. let mut cube_buf = Vec::new();
  67. let mut colour_buf = Vec::new();
  68. cube_buf.extend(&self.provided_len.to_le_bytes());
  69. colour_buf.extend(&self.provided_len.to_le_bytes());
  70. for c in self.into_iter() {
  71. cube_buf.extend(&c.dump_cube_data());
  72. colour_buf.extend(&c.dump_colour_data());
  73. }
  74. (cube_buf, colour_buf)
  75. }
  76. pub fn len(&self) -> usize {
  77. self.cubes.len()
  78. }
  79. }
  80. impl<'a> std::iter::IntoIterator for &'a Cubes {
  81. type Item = &'a Cube;
  82. type IntoIter = std::slice::Iter<'a, Cube>;
  83. fn into_iter(self) -> Self::IntoIter {
  84. self.cubes.iter()
  85. }
  86. }
  87. #[derive(Copy, Clone)]
  88. pub struct Cube {
  89. pub id: u32,
  90. pub x: u8, // left to right
  91. pub y: u8, // bottom to top
  92. pub z: u8, // back to front
  93. pub orientation: u8,
  94. pub colour: u8,
  95. }
  96. impl Cube {
  97. fn parse_cube_data(&mut self, reader: &mut &[u8]) -> Result<usize, ()> {
  98. let mut buf = [0; 4];
  99. // read cube id
  100. if let Ok(len) = reader.read(&mut buf) {
  101. if len != 4 {
  102. return Err(());
  103. }
  104. self.id = u32::from_le_bytes(buf);
  105. } else {
  106. return Err(());
  107. }
  108. // read x, y, z, orientation
  109. if let Ok(len) = reader.read(&mut buf) {
  110. if len != 4 {
  111. return Err(());
  112. }
  113. self.x = buf[0];
  114. self.y = buf[1];
  115. self.z = buf[2];
  116. self.orientation = buf[3];
  117. } else {
  118. return Err(());
  119. }
  120. Ok(8)
  121. }
  122. fn parse_colour_data(&mut self, reader: &mut &[u8]) -> Result<usize, ()> {
  123. let mut buf = [0; 4];
  124. if let Ok(len) = reader.read(&mut buf) {
  125. if len != 4 {
  126. return Err(());
  127. }
  128. self.colour = buf[0];
  129. } else {
  130. return Err(());
  131. }
  132. Ok(4)
  133. }
  134. pub fn dump_cube_data(&self) -> [u8; 8] {
  135. let id_buf = self.id.to_le_bytes();
  136. [id_buf[0], id_buf[1], id_buf[2], id_buf[3], self.x, self.y, self.z, self.orientation]
  137. }
  138. pub fn dump_colour_data(&self) -> [u8; 4] {
  139. [self.colour, self.x, self.y, self.z]
  140. }
  141. }
  142. impl std::default::Default for Cube {
  143. fn default() -> Self {
  144. Self {
  145. id: 0,
  146. x: 0,
  147. y: 0,
  148. z: 0,
  149. orientation: 0,
  150. colour: 0,
  151. }
  152. }
  153. }
  154. impl std::convert::From<crate::robocraft::FactoryRobotGetInfo> for Cubes {
  155. fn from(other: crate::robocraft::FactoryRobotGetInfo) -> Self {
  156. let mut cube_buf = Vec::new();
  157. let mut colour_buf = Vec::new();
  158. decode_config_buf(other.cube_data, STANDARD, &mut cube_buf).unwrap();
  159. decode_config_buf(other.colour_data, STANDARD, &mut colour_buf).unwrap();
  160. Self::parse(&mut cube_buf, &mut colour_buf).unwrap()
  161. }
  162. }
  163. impl std::convert::From<crate::robocraft::FactoryInfo<crate::robocraft::FactoryRobotGetInfo>> for Cubes {
  164. fn from(other: crate::robocraft::FactoryInfo<crate::robocraft::FactoryRobotGetInfo>) -> Self {
  165. Self::from(other.response)
  166. }
  167. }
  168. impl std::string::ToString for Cube {
  169. fn to_string(&self) -> String {
  170. format!("{{x: {}, y: {}, z: {}}} ({})", self.x, self.y, self.z, self.id)
  171. }
  172. }