diff --git a/src/app/validate/src/check_chunks.rs b/src/app/validate/src/check_chunks.rs index 2db59488..de1b0654 100644 --- a/src/app/validate/src/check_chunks.rs +++ b/src/app/validate/src/check_chunks.rs @@ -25,7 +25,7 @@ pub fn check_chunks(state: &ServerState) -> Result<(), String> { if chunk_format_hash_str != Chunk::type_hash() { error!( "Chunk format hash mismatch. Expected 0X{:0X}, got 0X{:0X}. This likely means that the chunk format has changed since saving. If you have \ - recently updated Temper you will have to go back to the older version until a world format converter is implemented.)", + recently updated Temper you will have to go back to the older version until a world format converter is implemented.", Chunk::type_hash(), chunk_format_hash_str ); @@ -36,7 +36,7 @@ pub fn check_chunks(state: &ServerState) -> Result<(), String> { "Could not find 'chunk-format-hash' in metadata. This likely means that the world was saved with an older version of Temper that did not include this metadata, or that the metadata is corrupted." ); error!( - "If you have recently updated Temper you will have to go back to the older version until a world format converter is implemented.)" + "If you have recently updated Temper you will have to go back to the older version until a world format converter is implemented." ); exit(1); } @@ -100,12 +100,12 @@ pub fn check_chunks(state: &ServerState) -> Result<(), String> { exit(1); } } - if let Err(e) = bitcode::decode::(&data) { + if let Err(e) = bitcode::deserialize::(&data) { progress_bar.finish(); error!("Chunk {} failed to decode: {}", decoded_key, e); error!( "This generally means that the chunk format has changed since saving. If you have \ - recently updated Temper you will have to go back to the older version until a world format converter is implemented.)" + recently updated Temper you will have to go back to the older version until a world format converter is implemented." ); exit(1); } diff --git a/src/base/logging/src/tui_formatter.rs b/src/base/logging/src/tui_formatter.rs index a8f19518..69c0130d 100644 --- a/src/base/logging/src/tui_formatter.rs +++ b/src/base/logging/src/tui_formatter.rs @@ -25,7 +25,7 @@ impl LogFormatter for TuiTracingFormatter { spans.push( evt.timestamp - .format("%Y-%m-%d %H:%M:%S | ") + .strftime("%Y-%m-%d %H:%M:%S | ") .to_string() .dim(), ); diff --git a/src/core/src/block_state_id.rs b/src/core/src/block_state_id.rs index 88731fa1..621dce9e 100644 --- a/src/core/src/block_state_id.rs +++ b/src/core/src/block_state_id.rs @@ -1,8 +1,8 @@ use crate::block_data::BlockData; use ahash::RandomState; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; use once_cell::sync::OnceCell; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt::Display; use std::process::exit; @@ -53,7 +53,7 @@ pub fn create_block_mappings() -> (Vec, HashMap for BlockPos { } } -#[derive(Clone, Copy, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, Copy, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct ChunkHeight { pub min_y: i16, pub height: u16, diff --git a/src/world/db/src/chunks.rs b/src/world/db/src/chunks.rs index bed4fe69..afe65557 100644 --- a/src/world/db/src/chunks.rs +++ b/src/world/db/src/chunks.rs @@ -19,7 +19,7 @@ pub fn save_chunk_internal( storage.create_table("chunks".to_string())?; } let as_bytes = yazi::compress( - &bitcode::encode(chunk), + &bitcode::serialize(chunk).expect("Unable to serialize chunk"), yazi::Format::Zlib, CompressionLevel::BestSpeed, )?; @@ -47,8 +47,8 @@ pub fn load_chunk_internal( warn!("Chunk data does not have a checksum, skipping verification."); } } - let chunk: Chunk = bitcode::decode(&data) - .map_err(|e| WorldError::BitcodeDecodeError(e.to_string()))?; + let chunk: Chunk = bitcode::deserialize(&data) + .map_err(|e| WorldError::BitcodeDeserializeError(e.to_string()))?; Ok(chunk) } None => Err(WorldError::ChunkNotFound), diff --git a/src/world/format/Cargo.toml b/src/world/format/Cargo.toml index 77a0d492..de6a4571 100644 --- a/src/world/format/Cargo.toml +++ b/src/world/format/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [dependencies] bitcode_derive = { workspace = true } -bitcode = { workspace = true } +bitcode = { workspace = true, features = ["serde"] } temper-codec = { workspace = true } temper-macros = { workspace = true } deepsize = { workspace = true } @@ -21,4 +21,16 @@ temper-nbt = { workspace = true } serde = { workspace = true } bytemuck = { workspace = true } tokio = { workspace = true } -type_hash = { workspace = true } \ No newline at end of file +type_hash = { workspace = true } + +[dev-dependencies] +criterion = { workspace = true } +rand = { workspace = true } + +[[bench]] + +name = "bench" +harness = false + + + diff --git a/src/world/format/benches/bench.rs b/src/world/format/benches/bench.rs new file mode 100644 index 00000000..325d969c --- /dev/null +++ b/src/world/format/benches/bench.rs @@ -0,0 +1,9 @@ +use criterion::{Criterion, criterion_group, criterion_main}; +mod serialize; + +fn world_format_bench(c: &mut Criterion) { + serialize::bench_serialize_world(c); +} + +criterion_group!(benches, world_format_bench); +criterion_main!(benches); diff --git a/src/world/format/benches/serialize.rs b/src/world/format/benches/serialize.rs new file mode 100644 index 00000000..a9b0dff1 --- /dev/null +++ b/src/world/format/benches/serialize.rs @@ -0,0 +1,38 @@ +use criterion::Criterion; +use std::hint::black_box; +use temper_core::block_state_id::BlockStateId; +use temper_core::pos::{ChunkBlockPos, ChunkHeight}; +use temper_world_format::Chunk; + +fn serialize_chunk(chunk: &mut Chunk) -> Vec { + black_box(bitcode::serialize(black_box(chunk)).unwrap()) +} + +pub fn bench_serialize_world(c: &mut Criterion) { + let mut chunk = Chunk::new_empty_with_height(ChunkHeight::new(-64, 384)); + for x in 0..16 { + for y in -64..320 { + for z in 0..16 { + if (x + z) % 3 == 0 { + chunk.set_block( + ChunkBlockPos::new(x, y, z), + BlockStateId::new(rand::random_range(0..20_000)), + ) + } + } + } + } + c.bench_function("format/Serialize", |b| { + b.iter(|| { + black_box(serialize_chunk(&mut chunk)); + }) + }); + + let serialized = serialize_chunk(&mut chunk); + + c.bench_function("format/Deserialize", |b| { + b.iter(|| { + black_box(bitcode::deserialize::(black_box(&serialized))).unwrap(); + }) + }); +} diff --git a/src/world/format/src/errors.rs b/src/world/format/src/errors.rs index c96268ce..1efb6288 100644 --- a/src/world/format/src/errors.rs +++ b/src/world/format/src/errors.rs @@ -27,10 +27,10 @@ pub enum WorldError { GenericIOError(String), #[error("A database error occurred from the world crate: {0}")] DatabaseError(StorageError), - #[error("There was an error with bitcode's decoding: {0}")] - BitcodeDecodeError(String), - #[error("There was an error with bitcode's encoding: {0}")] - BitcodeEncodeError(String), + #[error("There was an error with bitcode's deserializing: {0}")] + BitcodeDeserializeError(String), + #[error("There was an error with bitcode's serializing: {0}")] + BitcodeSerializeError(String), #[error("Chunk not found")] ChunkNotFound, #[error("Anvil Decode Error: {0}")] diff --git a/src/world/format/src/heightmap.rs b/src/world/format/src/heightmap.rs index 4b46bc44..ae19b973 100644 --- a/src/world/format/src/heightmap.rs +++ b/src/world/format/src/heightmap.rs @@ -1,19 +1,19 @@ use crate::errors::WorldError; use crate::vanilla_chunk_format::VanillaHeightmaps; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use temper_codec::net_types::length_prefixed_vec::LengthPrefixedVec; use temper_codec::net_types::var_int::VarInt; use temper_macros::NetEncode; use type_hash::TypeHash; -#[derive(Default, Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Default, Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct Heightmaps { pub world_surface: ChunkHeightmap, pub motion_blocking: ChunkHeightmap, } -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct ChunkHeightmap { data: Box<[i16]>, } diff --git a/src/world/format/src/lib.rs b/src/world/format/src/lib.rs index f520559a..000c2c7f 100644 --- a/src/world/format/src/lib.rs +++ b/src/world/format/src/lib.rs @@ -9,15 +9,15 @@ pub mod vanilla_chunk_format; use crate::errors::WorldError; use crate::heightmap::Heightmaps; use crate::section::{AIR, ChunkSection}; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use temper_core::block_state_id::BlockStateId; use temper_core::pos::{ChunkBlockPos, ChunkHeight}; use temper_macros::block; use type_hash::TypeHash; use vanilla_chunk_format::VanillaChunk; -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct Chunk { pub sections: Box<[ChunkSection]>, height: ChunkHeight, diff --git a/src/world/format/src/light/mod.rs b/src/world/format/src/light/mod.rs index f63569dd..bdf614b3 100644 --- a/src/world/format/src/light/mod.rs +++ b/src/world/format/src/light/mod.rs @@ -1,10 +1,10 @@ -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use type_hash::TypeHash; pub mod network; -#[derive(Default, Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Default, Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub(crate) enum LightStorage { #[default] Empty, @@ -14,7 +14,7 @@ pub(crate) enum LightStorage { }, } -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct SectionLightData { sky_light: LightStorage, block_light: LightStorage, diff --git a/src/world/format/src/palette.rs b/src/world/format/src/palette.rs index 763f0d7c..7fc9fbf7 100644 --- a/src/world/format/src/palette.rs +++ b/src/world/format/src/palette.rs @@ -1,6 +1,6 @@ use crate::section::AIR; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use std::num::NonZeroU16; use temper_core::block_state_id::BlockStateId; use type_hash::TypeHash; @@ -18,7 +18,7 @@ pub enum BlockPaletteResult { ConvertToUniform(BlockStateId), } -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct BlockPalette { pub(crate) palette: Vec>, pub(crate) free_count: u16, diff --git a/src/world/format/src/section/biome.rs b/src/world/format/src/section/biome.rs index f702b3bb..c4cee0bd 100644 --- a/src/world/format/src/section/biome.rs +++ b/src/world/format/src/section/biome.rs @@ -1,14 +1,16 @@ -use bitcode_derive::{Decode, Encode}; use bytemuck::{Pod, Zeroable}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use temper_core::pos::SectionBlockPos; use type_hash::TypeHash; #[repr(transparent)] -#[derive(Copy, Clone, Encode, Decode, Default, PartialEq, DeepSizeOf, Pod, Zeroable, TypeHash)] +#[derive( + Copy, Clone, Serialize, Deserialize, Default, PartialEq, DeepSizeOf, Pod, Zeroable, TypeHash, +)] pub struct BiomeType(pub u8); -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub enum BiomeData { Uniform(BiomeType), Mixed(Box<[BiomeType]>), diff --git a/src/world/format/src/section/direct.rs b/src/world/format/src/section/direct.rs index e5532132..c0407aa1 100644 --- a/src/world/format/src/section/direct.rs +++ b/src/world/format/src/section/direct.rs @@ -1,8 +1,8 @@ use crate::section::paletted::PalettedSection; use crate::section::uniform::UniformSection; use crate::section::{AIR, CHUNK_SECTION_LENGTH}; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use temper_core::block_state_id::BlockStateId; use type_hash::TypeHash; @@ -11,7 +11,7 @@ type CompactBlockStateId = u16; const AIR_COMPACT: CompactBlockStateId = AIR.raw() as CompactBlockStateId; -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct DirectSection(pub(crate) Box<[CompactBlockStateId]>, u16); impl Default for DirectSection { diff --git a/src/world/format/src/section/mod.rs b/src/world/format/src/section/mod.rs index 87af2509..aeec1100 100644 --- a/src/world/format/src/section/mod.rs +++ b/src/world/format/src/section/mod.rs @@ -5,8 +5,8 @@ use crate::section::direct::DirectSection; use crate::section::paletted::{PalettedSection, PalettedSectionResult}; use crate::section::uniform::UniformSection; use crate::vanilla_chunk_format::Section; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use temper_core::block_state_id::BlockStateId; use temper_core::pos::SectionBlockPos; use temper_macros::block; @@ -22,7 +22,7 @@ pub const CHUNK_SECTION_LENGTH: usize = 16 * 16 * 16; pub(crate) const AIR: BlockStateId = block!("air"); -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub(crate) enum ChunkSectionType { Uniform(UniformSection), Paletted(PalettedSection), @@ -95,7 +95,7 @@ impl ChunkSectionType { } } -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct ChunkSection { pub(crate) inner: ChunkSectionType, pub(crate) light: SectionLightData, diff --git a/src/world/format/src/section/paletted.rs b/src/world/format/src/section/paletted.rs index 9ce8754d..b6759997 100644 --- a/src/world/format/src/section/paletted.rs +++ b/src/world/format/src/section/paletted.rs @@ -2,8 +2,8 @@ use crate::BlockStateId; use crate::palette::{BlockPalette, BlockPaletteResult, PaletteIndex}; use crate::section::uniform::UniformSection; use crate::section::{AIR, CHUNK_SECTION_LENGTH}; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use std::num::NonZeroU16; use type_hash::TypeHash; @@ -13,7 +13,7 @@ pub enum PalettedSectionResult { Shrink(BlockStateId), } -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct PalettedSection { pub(crate) palette: BlockPalette, pub(crate) block_data: Box<[u64]>, diff --git a/src/world/format/src/section/uniform.rs b/src/world/format/src/section/uniform.rs index 7e5e9bd3..07e70182 100644 --- a/src/world/format/src/section/uniform.rs +++ b/src/world/format/src/section/uniform.rs @@ -1,10 +1,10 @@ use crate::BlockStateId; use crate::section::AIR; -use bitcode_derive::{Decode, Encode}; use deepsize::DeepSizeOf; +use serde_derive::{Deserialize, Serialize}; use type_hash::TypeHash; -#[derive(Clone, DeepSizeOf, Encode, Decode, TypeHash)] +#[derive(Clone, DeepSizeOf, Serialize, Deserialize, TypeHash)] pub struct UniformSection(BlockStateId); impl UniformSection { diff --git a/src/world/src/benches/edit_bench.rs b/src/world/src/benches/edit_bench.rs index 95399093..4aacd350 100644 --- a/src/world/src/benches/edit_bench.rs +++ b/src/world/src/benches/edit_bench.rs @@ -13,7 +13,7 @@ fn get_rand_in_range(min: i32, max: i32) -> i32 { #[expect(clippy::unit_arg)] pub(crate) fn bench_edits(c: &mut Criterion) { let chunk_data = include_bytes!("../../../../.etc/raw_chunk.dat"); - let chunk: Chunk = bitcode::decode(chunk_data) + let chunk: Chunk = bitcode::deserialize(chunk_data) .expect("If this fails, go run the dump_chunk test at src/lib/world/src/mod"); let mut read_group = c.benchmark_group("edit_read"); diff --git a/src/world/src/lib.rs b/src/world/src/lib.rs index 282d0035..1df3f871 100644 --- a/src/world/src/lib.rs +++ b/src/world/src/lib.rs @@ -175,7 +175,7 @@ mod tests { "Failed to load chunk. If it's a bitcode error, chances are the chunk format \ has changed since last generating a world so you'll need to regenerate", ); - let encoded = bitcode::encode(&*chunk); + let encoded = bitcode::serialize(&*chunk).unwrap(); std::fs::write("../../../.etc/raw_chunk.dat", encoded).unwrap(); } }