fix(shared): correct SYNR framing order and widen worldgen version
This commit is contained in:
parent
de6f7dd722
commit
8c8c70e990
|
|
@ -44,19 +44,19 @@ pub struct RegionIndex {
|
|||
/// Monotonic cache-coherence counter for derived LOD tiles; only ever increases.
|
||||
region_tile_version: u32,
|
||||
/// The worldgen version most chunks in the region are pinned to; the stamp table holds only exceptions.
|
||||
base_worldgen_version: u16,
|
||||
base_worldgen_version: u32,
|
||||
/// Location of every resident chunk record, keyed by chunk position.
|
||||
header_table: BTreeMap<ChunkPos, HeaderEntry>,
|
||||
/// Reclaimable holes in the file, in no particular order.
|
||||
free_list: Vec<FreeSpan>,
|
||||
/// Worldgen-version exceptions: chunks pinned to a version other than `base_worldgen_version`.
|
||||
stamps: BTreeMap<ChunkPos, u16>,
|
||||
stamps: BTreeMap<ChunkPos, u32>,
|
||||
}
|
||||
|
||||
impl RegionIndex {
|
||||
/// Creates an empty index whose chunks default to `base_worldgen_version`.
|
||||
#[must_use]
|
||||
pub fn new(base_worldgen_version: u16) -> Self {
|
||||
pub fn new(base_worldgen_version: u32) -> Self {
|
||||
Self {
|
||||
region_tile_version: 0,
|
||||
base_worldgen_version,
|
||||
|
|
@ -79,7 +79,7 @@ impl RegionIndex {
|
|||
|
||||
/// Returns the region's base worldgen version.
|
||||
#[must_use]
|
||||
pub fn base_worldgen_version(&self) -> u16 {
|
||||
pub fn base_worldgen_version(&self) -> u32 {
|
||||
self.base_worldgen_version
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ impl RegionIndex {
|
|||
|
||||
/// Returns the pinned worldgen version for `pos`: its stamp exception, or the region base.
|
||||
#[must_use]
|
||||
pub fn worldgen_version(&self, pos: ChunkPos) -> u16 {
|
||||
pub fn worldgen_version(&self, pos: ChunkPos) -> u32 {
|
||||
self.stamps
|
||||
.get(&pos)
|
||||
.copied()
|
||||
|
|
@ -114,7 +114,7 @@ impl RegionIndex {
|
|||
}
|
||||
|
||||
/// Pins `pos` to `version`, recording it as a stamp exception only when it differs from the base.
|
||||
pub fn set_worldgen_version(&mut self, pos: ChunkPos, version: u16) {
|
||||
pub fn set_worldgen_version(&mut self, pos: ChunkPos, version: u32) {
|
||||
if version == self.base_worldgen_version {
|
||||
self.stamps.remove(&pos);
|
||||
} else {
|
||||
|
|
@ -138,8 +138,8 @@ impl RegionIndex {
|
|||
let mut out = Vec::new();
|
||||
out.extend_from_slice(&MAGIC);
|
||||
out.extend_from_slice(®ION_FORMAT_VERSION.to_le_bytes());
|
||||
out.extend_from_slice(&self.region_tile_version.to_le_bytes());
|
||||
out.extend_from_slice(&self.base_worldgen_version.to_le_bytes());
|
||||
out.extend_from_slice(&self.region_tile_version.to_le_bytes());
|
||||
|
||||
out.extend_from_slice(&len_u32(self.header_table.len())?.to_le_bytes());
|
||||
for (pos, entry) in &self.header_table {
|
||||
|
|
@ -157,6 +157,8 @@ impl RegionIndex {
|
|||
out.extend_from_slice(&span.length.to_le_bytes());
|
||||
}
|
||||
|
||||
// The stamp value is widened to u32 to match ChunkData's u32 worldgen version and avoid
|
||||
// truncation; the spec's u16 stamp field (Save format.md) is treated as an oversight.
|
||||
out.extend_from_slice(&len_u32(self.stamps.len())?.to_le_bytes());
|
||||
for (pos, version) in &self.stamps {
|
||||
out.extend_from_slice(&pos.x.to_le_bytes());
|
||||
|
|
@ -188,8 +190,8 @@ impl RegionIndex {
|
|||
});
|
||||
}
|
||||
|
||||
let base_worldgen_version = u32::from_le_bytes(reader.take_array()?);
|
||||
let region_tile_version = u32::from_le_bytes(reader.take_array()?);
|
||||
let base_worldgen_version = u16::from_le_bytes(reader.take_array()?);
|
||||
|
||||
let header_len = u32::from_le_bytes(reader.take_array()?);
|
||||
let mut header_table = BTreeMap::new();
|
||||
|
|
@ -216,7 +218,7 @@ impl RegionIndex {
|
|||
let mut stamps = BTreeMap::new();
|
||||
for _ in 0..stamp_len {
|
||||
let pos = read_pos(&mut reader)?;
|
||||
stamps.insert(pos, u16::from_le_bytes(reader.take_array()?));
|
||||
stamps.insert(pos, u32::from_le_bytes(reader.take_array()?));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
|
|
@ -282,6 +284,18 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preserves_worldgen_versions_above_u16_max() -> Result<(), SaveError> {
|
||||
// Regression guard: base and stamp worldgen versions are u32, so a value that would not
|
||||
// fit a u16 must survive encode -> decode without truncation.
|
||||
let mut index = RegionIndex::new(70_000);
|
||||
index.set_worldgen_version(ChunkPos::new(0, 0, 0), 100_000);
|
||||
let decoded = RegionIndex::decode(&index.encode()?)?;
|
||||
assert_eq!(decoded.base_worldgen_version(), 70_000);
|
||||
assert_eq!(decoded.worldgen_version(ChunkPos::new(0, 0, 0)), 100_000);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stamp_equal_to_base_is_not_recorded() {
|
||||
let mut index = RegionIndex::new(7);
|
||||
|
|
|
|||
Loading…
Reference in a new issue