An unofficial collection of APIs used in FreeJam games and mods
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. use base64::{decode_config_buf, STANDARD};
  2. use std::io::Read;
  3. // TODO(maybe) parse iteratively instead of one-shot
  4. /// A collection of cube data
  5. ///
  6. /// This holds all data parsed from cube_data and colour_data.
  7. /// Individual Cube structs can be iterated through.
  8. #[derive(Clone)]
  9. pub struct Cubes {
  10. /// Parsed cube count (the first 32 bits of data parsed to `u32`)
  11. pub provided_len: u32,
  12. cubes: Vec<Cube>,
  13. }
  14. impl Cubes {
  15. /// Process the raw bytes containing block data from a Robocraft CRF bot
  16. ///
  17. /// `cube_data` and `colour_data` correspond to the `cube_data` and `colour_data` fields of FactoryRobotGetInfo.
  18. /// In general, you should use `Cubes::from<FactoryRobotGetInfo>(data)` instead of this lower-level function.
  19. pub fn parse(cube_data: &mut Vec<u8>, colour_data: &mut Vec<u8>) -> Result<Self, ()> {
  20. // read first 4 bytes (cube count) from both arrays and make sure they match
  21. let mut cube_buf = [0; 4];
  22. let mut colour_buf = [0; 4];
  23. let mut cube_slice = cube_data.as_slice();
  24. let mut colour_slice = colour_data.as_slice();
  25. if let Ok(len) = cube_slice.read(&mut cube_buf) {
  26. if len != 4 {
  27. //println!("Failed reading cube_data len");
  28. return Err(());
  29. }
  30. } else {
  31. //println!("Failed to read cube_data");
  32. return Err(());
  33. }
  34. if let Ok(len) = colour_slice.read(&mut colour_buf) {
  35. if len != 4 {
  36. //println!("Failed reading colour_data len");
  37. return Err(());
  38. }
  39. } else {
  40. //println!("Failed to read colour_data");
  41. return Err(());
  42. }
  43. if !(cube_buf[0] == colour_buf[0]
  44. && cube_buf[1] == colour_buf[1]
  45. && cube_buf[2] == colour_buf[2]
  46. && cube_buf[3] == colour_buf[3]) {
  47. //println!("Values do not match");
  48. return Err(());
  49. }
  50. let mut cube_i = 4;
  51. let mut colour_i = 4;
  52. let mut parsed_cubes = Vec::with_capacity(cube_data.len() / 8);
  53. while cube_i < cube_data.len() && colour_i < colour_data.len() {
  54. let mut new_cube = Cube::default();
  55. if let Ok(cube_add) = new_cube.parse_cube_data(&mut cube_slice) {
  56. if let Ok(colour_add) = new_cube.parse_colour_data(&mut colour_slice) {
  57. cube_i += cube_add;
  58. colour_i += colour_add;
  59. parsed_cubes.push(new_cube);
  60. } else {
  61. // colour_data read error
  62. return Err(());
  63. }
  64. } else {
  65. // cube_data read error
  66. return Err(());
  67. }
  68. }
  69. Ok(Self {
  70. provided_len: u32::from_le_bytes(cube_buf),
  71. cubes: parsed_cubes,
  72. })
  73. }
  74. /// Dump the raw bytes containing block data for a Robocraft bot.
  75. ///
  76. /// The first tuple item is cube data, and the second item is colour data.
  77. /// Use this to write a modified robot to file.
  78. /// This is the inverse of `Cubes::parse(...)`.
  79. ///
  80. /// I'm not sure what this would actually be useful for...
  81. pub fn dump(&self) -> (Vec<u8>, Vec<u8>) {
  82. let mut cube_buf = Vec::new();
  83. let mut colour_buf = Vec::new();
  84. cube_buf.extend(&self.provided_len.to_le_bytes());
  85. colour_buf.extend(&self.provided_len.to_le_bytes());
  86. for c in self.into_iter() {
  87. cube_buf.extend(&c.dump_cube_data());
  88. colour_buf.extend(&c.dump_colour_data());
  89. }
  90. (cube_buf, colour_buf)
  91. }
  92. /// Get the actual amount of cubes.
  93. ///
  94. /// This differs from `provided_len` by being the amount of cubes parsed (successfully), instead of something parsed from block data.
  95. /// For any valid robot data, `data.provided_len == data.len()`.
  96. pub fn len(&self) -> usize {
  97. self.cubes.len()
  98. }
  99. }
  100. impl<'a> std::iter::IntoIterator for &'a Cubes {
  101. type Item = &'a Cube;
  102. type IntoIter = std::slice::Iter<'a, Cube>;
  103. fn into_iter(self) -> Self::IntoIter {
  104. self.cubes.iter()
  105. }
  106. }
  107. /// A single block in a Robocraft robot.
  108. ///
  109. /// From the front of a Robocraft garage bay, looking at the back, all positions are measured from the back bottom right corner.
  110. #[derive(Copy, Clone)]
  111. pub struct Cube {
  112. /// The cube id
  113. pub id: u32,
  114. /// The cube's x position (left to right)
  115. pub x: u8, // left to right
  116. /// The cube's y position (bottom to top)
  117. pub y: u8, // bottom to top
  118. /// The cube's z position (back to front)
  119. pub z: u8, // back to front
  120. /// The cube's orientation
  121. pub orientation: u8,
  122. /// The cube's colour, one of the 24 possible colours in Robocraft
  123. pub colour: u8,
  124. }
  125. impl Cube {
  126. fn parse_cube_data(&mut self, reader: &mut dyn Read) -> Result<usize, ()> {
  127. let mut buf = [0; 4];
  128. // read cube id
  129. if let Ok(len) = reader.read(&mut buf) {
  130. if len != 4 {
  131. return Err(());
  132. }
  133. self.id = u32::from_le_bytes(buf);
  134. } else {
  135. return Err(());
  136. }
  137. // read x, y, z, orientation
  138. if let Ok(len) = reader.read(&mut buf) {
  139. if len != 4 {
  140. return Err(());
  141. }
  142. self.x = buf[0];
  143. self.y = buf[1];
  144. self.z = buf[2];
  145. self.orientation = buf[3];
  146. } else {
  147. return Err(());
  148. }
  149. Ok(8)
  150. }
  151. fn parse_colour_data(&mut self, reader: &mut dyn Read) -> Result<usize, ()> {
  152. let mut buf = [0; 4];
  153. if let Ok(len) = reader.read(&mut buf) {
  154. if len != 4 {
  155. return Err(());
  156. }
  157. self.colour = buf[0];
  158. } else {
  159. return Err(());
  160. }
  161. Ok(4)
  162. }
  163. /// Dump the raw cube data as used in the Robocraft CRF.
  164. ///
  165. /// This is useless by itself, use `Cubes.dump()` for a valid robot.
  166. pub fn dump_cube_data(&self) -> [u8; 8] {
  167. let id_buf = self.id.to_le_bytes();
  168. [id_buf[0], id_buf[1], id_buf[2], id_buf[3], self.x, self.y, self.z, self.orientation]
  169. }
  170. /// Dump the raw colour data as used in the Robocraft CRF.
  171. ///
  172. /// This is useless by itself, use `Cubes.dump()` for a valid robot.
  173. pub fn dump_colour_data(&self) -> [u8; 4] {
  174. [self.colour, self.x, self.y, self.z]
  175. }
  176. }
  177. impl std::default::Default for Cube {
  178. fn default() -> Self {
  179. Self {
  180. id: 0,
  181. x: 0,
  182. y: 0,
  183. z: 0,
  184. orientation: 0,
  185. colour: 0,
  186. }
  187. }
  188. }
  189. impl std::convert::From<crate::robocraft::FactoryRobotGetInfo> for Cubes {
  190. fn from(other: crate::robocraft::FactoryRobotGetInfo) -> Self {
  191. let mut cube_buf = Vec::new();
  192. let mut colour_buf = Vec::new();
  193. decode_config_buf(other.cube_data, STANDARD, &mut cube_buf).unwrap();
  194. decode_config_buf(other.colour_data, STANDARD, &mut colour_buf).unwrap();
  195. Self::parse(&mut cube_buf, &mut colour_buf).unwrap()
  196. }
  197. }
  198. impl std::convert::From<crate::robocraft::FactoryInfo<crate::robocraft::FactoryRobotGetInfo>> for Cubes {
  199. fn from(other: crate::robocraft::FactoryInfo<crate::robocraft::FactoryRobotGetInfo>) -> Self {
  200. Self::from(other.response)
  201. }
  202. }
  203. impl std::string::ToString for Cube {
  204. fn to_string(&self) -> String {
  205. format!("{{x: {}, y: {}, z: {}}} ({})", self.x, self.y, self.z, self.id)
  206. }
  207. }