From fcefa22c073e1c91428341d32f0f27d416d26f2b Mon Sep 17 00:00:00 2001 From: kaiyohugo <41114603+KAIYOHUGO@users.noreply.github.com> Date: Sun, 12 May 2024 16:30:11 +0800 Subject: [PATCH 1/2] Fix mcpe example --- examples/mcpe/src/main.rs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/examples/mcpe/src/main.rs b/examples/mcpe/src/main.rs index 65360cd..e0a6f13 100644 --- a/examples/mcpe/src/main.rs +++ b/examples/mcpe/src/main.rs @@ -1,8 +1,10 @@ use miniz_oxide::deflate::{compress_to_vec, compress_to_vec_zlib}; use miniz_oxide::inflate::{decompress_to_vec, decompress_to_vec_zlib}; +use rusty_leveldb::compressor::NoneCompressor; use rusty_leveldb::{Compressor, CompressorList, Options, DB}; use std::rc::Rc; +/// A zlib compressor that with zlib wrapper struct ZlibCompressor(u8); impl ZlibCompressor { @@ -26,6 +28,15 @@ impl Compressor for ZlibCompressor { } } +/// A zlib compressor that without zlib wrapper +/// +/// > windowBits can also be –8..–15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute a check value. +/// > +/// > From [zlib manual](https://zlib.net/manual.html) +/// +/// It seems like mojang use this most +/// +/// A copy of mojang's implementation can be find [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/db/zlib_compressor.cc#L119). struct RawZlibCompressor(u8); impl RawZlibCompressor { @@ -51,18 +62,30 @@ impl Compressor for RawZlibCompressor { pub fn mcpe_options(compression_level: u8) -> Options { let mut opt = Options::default(); - opt.compressor = 0; + + // compressor id list can be find in [mojang's implementation](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/include/leveldb/c.h#L194-L200) + // And it seems like mojang don't use slippy or zstd of minecraft bedrock + // + // If you need to open old world, old world fallback compressor can be find [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/bedrock_leveldb.c#L152-L153) let mut list = CompressorList::new(); - list.set_with_id(0, RawZlibCompressor::new(compression_level)); - list.set_with_id(1, ZlibCompressor::new(compression_level)); + list.set_with_id(0, NoneCompressor::default()); + list.set_with_id(2, ZlibCompressor::new(compression_level)); + list.set_with_id(4, RawZlibCompressor::new(compression_level)); opt.compressor_list = Rc::new(list); + + // Set compressor + // Minecraft bedrock may use other id than 4 + // + // There is a bug in this library that you have to open a database with the same compression type as it was written to. + opt.compressor = 4; + opt } fn main() { let path = "mcpe_db"; - let compression_level = 10; - let opt = mcpe_options(compression_level); + const COMPRESSION_LEVEL: u8 = 10; + let opt = mcpe_options(COMPRESSION_LEVEL); let mut db = DB::open(path, opt).unwrap(); db.put(b"~local_player", b"NBT data goes here").unwrap(); let value = db.get(b"~local_player").unwrap(); From 7b0b9cabe3493a9d38030099d4a1b76e05781110 Mon Sep 17 00:00:00 2001 From: kaiyohugo <41114603+KAIYOHUGO@users.noreply.github.com> Date: Wed, 15 May 2024 20:09:53 +0800 Subject: [PATCH 2/2] Add more comment about Mojang's implementation --- examples/mcpe/src/main.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/examples/mcpe/src/main.rs b/examples/mcpe/src/main.rs index e0a6f13..830a38a 100644 --- a/examples/mcpe/src/main.rs +++ b/examples/mcpe/src/main.rs @@ -1,14 +1,16 @@ -use miniz_oxide::deflate::{compress_to_vec, compress_to_vec_zlib}; +use miniz_oxide::deflate::{compress_to_vec, compress_to_vec_zlib, CompressionLevel}; use miniz_oxide::inflate::{decompress_to_vec, decompress_to_vec_zlib}; use rusty_leveldb::compressor::NoneCompressor; use rusty_leveldb::{Compressor, CompressorList, Options, DB}; use std::rc::Rc; /// A zlib compressor that with zlib wrapper +/// +/// This is use for old world format struct ZlibCompressor(u8); impl ZlibCompressor { - /// level 0-10 + /// compression level 0-10 pub fn new(level: u8) -> Self { assert!(level <= 10); Self(level) @@ -34,13 +36,13 @@ impl Compressor for ZlibCompressor { /// > /// > From [zlib manual](https://zlib.net/manual.html) /// -/// It seems like mojang use this most -/// -/// A copy of mojang's implementation can be find [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/db/zlib_compressor.cc#L119). +/// It seems like Mojang use this for newer version +/// +/// A copy of Mojang's implementation can be find [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/db/zlib_compressor.cc#L119). struct RawZlibCompressor(u8); impl RawZlibCompressor { - /// level 0-10 + /// compression level 0-10 pub fn new(level: u8) -> Self { assert!(level <= 10); Self(level) @@ -63,10 +65,13 @@ impl Compressor for RawZlibCompressor { pub fn mcpe_options(compression_level: u8) -> Options { let mut opt = Options::default(); - // compressor id list can be find in [mojang's implementation](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/include/leveldb/c.h#L194-L200) - // And it seems like mojang don't use slippy or zstd of minecraft bedrock + // Mojang create a custom [compressor list](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/include/leveldb/options.h#L123) + // Sample config for compressor list can be find in [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/mcpe_sample_setup.cpp#L24-L28) // - // If you need to open old world, old world fallback compressor can be find [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/bedrock_leveldb.c#L152-L153) + // Their compression id can be find in [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/include/leveldb/zlib_compressor.h#L38) + // and [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/include/leveldb/zlib_compressor.h#L48) + // + // Compression id will be use in [here](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/table/format.cc#L125-L150) let mut list = CompressorList::new(); list.set_with_id(0, NoneCompressor::default()); list.set_with_id(2, ZlibCompressor::new(compression_level)); @@ -74,19 +79,25 @@ pub fn mcpe_options(compression_level: u8) -> Options { opt.compressor_list = Rc::new(list); // Set compressor - // Minecraft bedrock may use other id than 4 + // Minecraft bedrock may use other id than 4 however default is 4. [Mojang's implementation](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/table/table_builder.cc#L152) // // There is a bug in this library that you have to open a database with the same compression type as it was written to. + // If raw data is smaller than compression, Mojang will use raw data. [Mojang's implementation](https://github.com/reedacartwright/rbedrock/blob/fb32a899da4e15c1aaa0d6de2b459e914e183516/src/leveldb-mcpe/table/table_builder.cc#L155-L165) + // There is a small chance that compression id 0 exists, you should use compression id 0 to write it. opt.compressor = 4; opt } +/// Path to world's db folder +const PATH: &str = "mcpe_db"; + +/// Mojang use `DefaultLevel` for world compression +const COMPRESSION_LEVEL: u8 = CompressionLevel::DefaultLevel as u8; + fn main() { - let path = "mcpe_db"; - const COMPRESSION_LEVEL: u8 = 10; let opt = mcpe_options(COMPRESSION_LEVEL); - let mut db = DB::open(path, opt).unwrap(); + let mut db = DB::open(PATH, opt).unwrap(); db.put(b"~local_player", b"NBT data goes here").unwrap(); let value = db.get(b"~local_player").unwrap(); assert_eq!(&value, b"NBT data goes here")