From 404ad74235cc69935204ea50497a80f9acce6aad Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Wed, 12 Mar 2025 20:54:04 +0100
Subject: [PATCH] core: deserialize biome list into Vec

Only use IndexSet for deduplication while processing the biome; when
deserializing, no deduplication is required, so using a Vec is faster
(besides IndexSet missing non-serde support for bincode 2).
---
 src/core/common.rs           |  3 +--
 src/core/region_processor.rs | 12 ++++++++++--
 src/core/tile_renderer.rs    |  2 +-
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/src/core/common.rs b/src/core/common.rs
index 8230a79..b25d7b8 100644
--- a/src/core/common.rs
+++ b/src/core/common.rs
@@ -8,7 +8,6 @@ use std::{
 
 use anyhow::{Context, Result};
 use clap::ValueEnum;
-use indexmap::IndexSet;
 use regex::{Regex, RegexSet};
 use serde::{Deserialize, Serialize};
 
@@ -102,7 +101,7 @@ pub struct ProcessedRegion {
 	/// List of biomes used in the region
 	///
 	/// Indexed by [ProcessedChunk] biome data
-	pub biome_list: IndexSet<Biome>,
+	pub biome_list: Vec<Biome>,
 	/// Processed chunk data
 	pub chunks: ChunkArray<Option<Box<ProcessedChunk>>>,
 }
diff --git a/src/core/region_processor.rs b/src/core/region_processor.rs
index e448f5e..1dc50fb 100644
--- a/src/core/region_processor.rs
+++ b/src/core/region_processor.rs
@@ -1,9 +1,11 @@
 //! The [RegionProcessor] and related functions
 
-use std::{ffi::OsStr, path::PathBuf, sync::mpsc, time::SystemTime};
+use std::{ffi::OsStr, mem, path::PathBuf, sync::mpsc, time::SystemTime};
 
 use anyhow::{Context, Result};
 use enum_map::{Enum, EnumMap};
+use indexmap::IndexSet;
+use minedmap_resource::Biome;
 use rayon::prelude::*;
 use tracing::{debug, info, warn};
 
@@ -73,6 +75,8 @@ struct SingleRegionProcessor<'a> {
 	lightmap_needed: bool,
 	/// True if entity output file needs to be updated
 	entities_needed: bool,
+	/// [IndexSet] of biomes used by the processed region
+	biome_list: IndexSet<Biome>,
 	/// Processed region intermediate data
 	processed_region: ProcessedRegion,
 	/// Lightmap intermediate data
@@ -108,6 +112,7 @@ impl<'a> SingleRegionProcessor<'a> {
 		let entities_needed = Some(input_timestamp) > entities_timestamp;
 
 		let processed_region = ProcessedRegion::default();
+		let biome_list = IndexSet::default();
 		let lightmap = image::GrayAlphaImage::new(N, N);
 		let entities = ProcessedEntities::default();
 
@@ -127,6 +132,7 @@ impl<'a> SingleRegionProcessor<'a> {
 			lightmap_needed,
 			entities_needed,
 			processed_region,
+			biome_list,
 			lightmap,
 			entities,
 			image_format: processor.config.tile_image_format(),
@@ -220,7 +226,7 @@ impl<'a> SingleRegionProcessor<'a> {
 				biomes,
 				block_light,
 				depths,
-			}) = world::layer::top_layer(&mut self.processed_region.biome_list, &chunk)
+			}) = world::layer::top_layer(&mut self.biome_list, &chunk)
 				.with_context(|| format!("Failed to process chunk {:?}", chunk_coords))?
 			{
 				if self.output_needed {
@@ -291,6 +297,8 @@ impl<'a> SingleRegionProcessor<'a> {
 			}
 		}
 
+		self.processed_region.biome_list = mem::take(&mut self.biome_list).into_iter().collect();
+
 		self.save_region()?;
 		self.save_lightmap()?;
 		self.save_entities()?;
diff --git a/src/core/tile_renderer.rs b/src/core/tile_renderer.rs
index 24af234..e47e20e 100644
--- a/src/core/tile_renderer.rs
+++ b/src/core/tile_renderer.rs
@@ -187,7 +187,7 @@ impl<'a> TileRenderer<'a> {
 
 		for ((region_x, region_z, index), w) in weights.into_values() {
 			let region = region_group.get(region_x, region_z)?;
-			let biome = region.biome_list.get_index(index.into())?;
+			let biome = region.biome_list.get(usize::from(index))?;
 
 			total += w;
 			color += w * block_color(block, Some(biome), depth.0 as f32);