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.

115 lines
4.1KB

  1. use chrono::{naive::NaiveDate, Datelike};
  2. use std::io::{Read, Write};
  3. use crate::techblox::{EntityHeader, BlockGroupEntity, parse_i64, parse_u32, Parsable, SerializedEntityDescriptor};
  4. use crate::techblox::blocks::lookup_hashname;
  5. /// A collection of cubes and other data from a GameSave.techblox file
  6. //#[derive(Clone)]
  7. pub struct GameSave {
  8. /// Game version that this save was created by.
  9. /// This may affect how the rest of the save file was parsed.
  10. pub version: NaiveDate,
  11. /// Unused magic value in file header.
  12. pub magic1: i64,
  13. /// Amount of cubes present in the save data, as claimed by the file header.
  14. pub cube_len: u32,
  15. /// Unused magic value in file header.
  16. pub magic2: u32,
  17. /// Amount of block groups, as claimed by the file header.
  18. pub group_len: u32,
  19. /// Entity group descriptors for block group entities.
  20. pub group_headers: Vec<EntityHeader>,
  21. /// Block group entities.
  22. pub cube_groups: Vec<BlockGroupEntity>,
  23. /// Entity group descriptors for block entities.
  24. pub cube_headers: Vec<EntityHeader>,
  25. /// Blocks
  26. pub cube_entities: Vec<Box<dyn SerializedEntityDescriptor>>
  27. }
  28. impl Parsable for GameSave {
  29. /// Process a Techblox save file from raw bytes.
  30. fn parse(data: &mut dyn Read) -> std::io::Result<Self> {
  31. // parse version
  32. let year = parse_u32(data)?; // parsed as i32 in-game for some reason
  33. let month = parse_u32(data)?;
  34. let day = parse_u32(data)?;
  35. let date = NaiveDate::from_ymd(year as i32, month, day);
  36. let magic_val1 = parse_i64(data)?; // unused
  37. let cube_count = parse_u32(data)?; // parsed as i32 in-game for some reason
  38. let magic_val2 = parse_u32(data)?; // unused
  39. let group_count = parse_u32(data)?; // parsed as i32 in-game for some reason
  40. // parse block groups
  41. let mut groups_h = Vec::<EntityHeader>::with_capacity(group_count as usize);
  42. let mut groups_e = Vec::<BlockGroupEntity>::with_capacity(group_count as usize);
  43. for _i in 0..group_count {
  44. groups_h.push(EntityHeader::parse(data)?);
  45. groups_e.push(BlockGroupEntity::parse(data)?);
  46. }
  47. // parse cube data
  48. let mut cubes_h = Vec::<EntityHeader>::with_capacity(cube_count as usize);
  49. let mut cubes_e = Vec::<Box<dyn SerializedEntityDescriptor>>::with_capacity(cube_count as usize);
  50. for _i in 0..cube_count {
  51. let header = EntityHeader::parse(data)?;
  52. let hash = header.hash;
  53. cubes_h.push(header);
  54. cubes_e.push(lookup_hashname(hash, data)?);
  55. }
  56. // TODO
  57. Ok(Self {
  58. version: date,
  59. magic1: magic_val1,
  60. cube_len: cube_count,
  61. magic2: magic_val2,
  62. group_len: group_count,
  63. group_headers: groups_h,
  64. cube_groups: groups_e,
  65. cube_headers: cubes_h,
  66. cube_entities: cubes_e,
  67. })
  68. }
  69. fn dump(&self, writer: &mut dyn Write) -> std::io::Result<usize> {
  70. let mut write_count: usize = 0;
  71. // version
  72. write_count += self.version.year().dump(writer)?;
  73. write_count += self.version.month().dump(writer)?;
  74. write_count += self.version.day().dump(writer)?;
  75. // magic separator
  76. write_count += self.magic1.dump(writer)?;
  77. write_count += self.cube_len.dump(writer)?;
  78. // magic separator
  79. write_count += self.magic2.dump(writer)?;
  80. write_count += self.group_len.dump(writer)?;
  81. // dump block groups
  82. for i in 0..self.group_len as usize {
  83. write_count += self.group_headers[i].dump(writer)?;
  84. write_count += self.cube_groups[i].dump(writer)?;
  85. }
  86. // dump cube data
  87. for i in 0..self.cube_len as usize {
  88. write_count += self.cube_headers[i].dump(writer)?;
  89. write_count += self.cube_entities[i].dump(writer)?;
  90. }
  91. // TODO
  92. Ok(write_count)
  93. }
  94. }
  95. impl std::string::ToString for GameSave {
  96. fn to_string(&self) -> String {
  97. format!("{}g {}c (v{})", self.group_len, self.cube_len, self.version)
  98. }
  99. }