Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fix]: Fixed lots of bugs in the Level implementation #118

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9d633a3
Allow users to specify default implementation for level
akashic-records-of-the-abyss Jan 1, 2025
e8ee6c8
Merge branch 'bedrock-crustaceans:main' into proto_rework
akashic-records-of-the-abyss Jan 1, 2025
0749d80
Merge pull request #1 from akashic-records-of-the-abyss/proto_rework
akashic-records-of-the-abyss Jan 1, 2025
bca2217
Update Cargo.toml
akashic-records-of-the-abyss Jan 1, 2025
edf176c
changed syntax
akashic-records-of-the-abyss Jan 1, 2025
d180db8
Update Cargo.toml
akashic-records-of-the-abyss Jan 1, 2025
e8a629a
added propper close methods
akashic-records-of-the-abyss Jan 4, 2025
5328546
added filling function and fixed writer bugs
akashic-records-of-the-abyss Jan 4, 2025
7c647a5
Changed how the project is included
akashic-records-of-the-abyss Jan 4, 2025
dc314cd
Cleaned up fill function
akashic-records-of-the-abyss Jan 4, 2025
449cde3
Made the level APIs more user friendly
akashic-records-of-the-abyss Jan 4, 2025
ee2d460
Made clippy happy
akashic-records-of-the-abyss Jan 4, 2025
b52b662
Revert "Made clippy happy"
akashic-records-of-the-abyss Jan 4, 2025
4486a11
Reapply "Made clippy happy"
akashic-records-of-the-abyss Jan 4, 2025
c22917f
Merge branch 'dev' into proto_rework
akashic-records-of-the-abyss Jan 4, 2025
20c15ad
Merge branch 'main' into proto_rework
akashic-records-of-the-abyss Jan 4, 2025
b270416
Merge pull request #2 from akashic-records-of-the-abyss/proto_rework
akashic-records-of-the-abyss Jan 4, 2025
d613875
Began on examples
akashic-records-of-the-abyss Jan 4, 2025
8234eb5
Addressed issues with imports
akashic-records-of-the-abyss Jan 4, 2025
6f7750b
Continued working on examples
akashic-records-of-the-abyss Jan 4, 2025
c9110d3
Added deleting to the API
akashic-records-of-the-abyss Jan 4, 2025
6c8601c
Made config public
akashic-records-of-the-abyss Jan 4, 2025
a136f46
Merge branch 'world_examples' into proto_rework
akashic-records-of-the-abyss Jan 4, 2025
6c4c205
Added better getter for chunk
akashic-records-of-the-abyss Jan 4, 2025
cab5541
Merge branch 'proto_rework' of https://github.com/akashic-records-of-…
akashic-records-of-the-abyss Jan 4, 2025
ea312fe
Update Cargo.toml
theaddonn Jan 4, 2025
810f5be
Fixed tests
akashic-records-of-the-abyss Jan 4, 2025
434d5b6
Pushed level
akashic-records-of-the-abyss Jan 4, 2025
00ed1ce
Tried a hack
akashic-records-of-the-abyss Jan 4, 2025
d9d7026
Update Cargo.toml
theaddonn Jan 4, 2025
401be96
Removed example for now
akashic-records-of-the-abyss Jan 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ bedrockrs_proto_core = { path = "crates/proto_core", optional = true }

bedrockrs_server = { path = "crates/server", optional = true }

bedrockrs_level = {path = "crates/level", optional = true}
bedrockrs_level = { path = "crates/level", optional = true }

[dev-dependencies]
tokio = { version = "1.40", features = ["full"] }
Expand All @@ -35,14 +35,18 @@ log = "0.4"
chrono = "0.4"

[features]
default = ["full"]

addon = ["dep:bedrockrs_addon"]
proto = ["dep:bedrockrs_proto","dep:bedrockrs_proto_core","dep:bedrockrs_macros",]
level = ["dep:bedrockrs_level"]
full = ["addon", "level", "proto", "server"]
form = ["dep:bedrockrs_form"]
proto = ["dep:bedrockrs_proto", "dep:bedrockrs_proto_core", "dep:bedrockrs_macros", ]
level = ["dep:bedrockrs_level", "level-default"]
server = ["dep:bedrockrs_server", "proto", "level", "form"]

level-default = ["bedrockrs_level/default-impl"]

full = ["addon", "form", "proto", "level", "server", "level-default"]

[[example]]
name = "proto_server"
path = "examples/proto/server.rs"
Expand All @@ -52,3 +56,4 @@ required-features = ["proto"]
name = "proto_parsing"
path = "examples/proto_parsing.rs"
required-features = ["proto"]

21 changes: 11 additions & 10 deletions crates/level/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,29 @@ version = "0.1.0"
edition = "2021"
akashic-records-of-the-abyss marked this conversation as resolved.
Show resolved Hide resolved

[dependencies]
bedrockrs_core = { path = "../core" }
bedrockrs_shared = { path = "../shared" }

nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" }


thiserror = "2.0"
byteorder = "1.x"
uuid = { version = "1.x", features = ["v4"] }
byteorder = "1.5"
uuid = { version = "1.11", features = ["v4"] }
bytemuck = { version = "1.19", features = ["must_cast"] }
len-trait = "0.6"
concat-idents = "1.x"
serde = "1.x.x"
rusty-leveldb = "3.x"
serde = "1.0"
rusty-leveldb = "3.0"
miniz_oxide = "0.8"
vek = "0.17"

[dev-dependencies]
rand = "0.8"

[features]
default-impl = []

[[test]]
name = "api_test"
required-features = ["default-impl"]


[features]
default-impl = []
default = ["default-impl"]

23 changes: 13 additions & 10 deletions crates/level/src/level/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
/// # Parameters
/// - A boxed function with the following parameters:
/// - `&UserBlockType`: The current block being evaluated.
/// - `Vec3<u8>`: The local coordinates of the block within the chunk.
/// - `Vec3<u8>`: The local coordinates of the block within the current subchunk.
/// - `Vec2<i32>`: The world-space XZ coordinates of the chunk.
/// - `i8`: The subchunk y.
///
Expand All @@ -40,6 +40,17 @@
Precedence(Box<dyn Fn(&UserBlockType, Vec3<u8>, Vec2<i32>, i8) -> bool>),
}

impl<T: WorldBlockTrait> FillFilter<T> {
pub fn may_place(&self, target: &T, position: Vec3<u8>, xz: Vec2<i32>, y: i8) -> bool {
match self {
FillFilter::Blanket => true,
FillFilter::Replace(v) => v == target,
FillFilter::Avoid(v) => v != target,
FillFilter::Precedence(f) => f(target, position, xz, y),
}
}
}

#[derive(Error, Debug)]
pub enum FillError {
#[error("Attempted to fill Subchunk {0} and got none back")]
Expand Down Expand Up @@ -369,7 +380,7 @@
/// - `Blanket`: Fills all blocks unconditionally.
/// - `Replace(mask)`: Replaces only blocks matching the given mask.
/// - `Avoid(mask)`: Fills blocks that do not match the mask.
/// - `Precedence(func)`: Uses a custom function to determine if a block should be replaced.

Check warning on line 383 in crates/level/src/level/chunk.rs

View workflow job for this annotation

GitHub Actions / Clippy

empty line after doc comment

pub fn fill_chunk(&mut self, block: UserBlockType, filter: FillFilter<UserBlockType>) -> Result<&mut Self, FillError> {
let pos = self.pos();
Expand All @@ -382,15 +393,7 @@
let blk = subchunk
.get_block((x, y, z).into())
.ok_or(FillError::BlockIndexDidntReturn(x, y, z))?;
if match &filter {
FillFilter::Blanket => true,
FillFilter::Replace(mask) =>
mask == blk,
FillFilter::Avoid(mask) => mask != blk,
FillFilter::Precedence(func) => {
func(blk, (x, y, z).into(), pos, subchunk.get_y())
}
} {
if filter.may_place(blk, (x, y, z).into(), pos, y_level) {
subchunk.set_block((x, y, z).into(), block.clone()).unwrap()
}
}
Expand Down Expand Up @@ -464,7 +467,7 @@
bounds: min_max,
xz,
dim,
sections: unsafe { std::mem::transmute(subchunk_list) },

Check warning on line 470 in crates/level/src/level/chunk.rs

View workflow job for this annotation

GitHub Actions / Clippy

transmute used without annotations
phantom_data: PhantomData,
_phantom_data: PhantomData
})
Expand Down
2 changes: 1 addition & 1 deletion crates/level/src/level/db_interface/bedrock_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl LevelDBKey for ChunkKey {
size += std::mem::size_of::<i32>();
}
size += 1; // For the key_type
if let Some(_) = self.y_index {
if self.y_index.is_some() {
size += 1;
}
size
Expand Down
29 changes: 16 additions & 13 deletions crates/level/src/level/db_interface/rusty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,11 +113,17 @@ impl<UserState> RustyDBInterface<UserState> {
}
}

impl<T> Drop for RustyDBInterface<T> {
fn drop(&mut self) {
self.db.close().unwrap();
}
}

impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
type Err = DBError;
type UserState = UserState;

fn set_subchunk_raw(
fn write_bytes_to_key(
&mut self,
chunk_info: ChunkKey,
chunk_bytes: &[u8],
Expand All @@ -128,20 +134,20 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
Ok(self.db.write(batch, false)?)
}

fn get_subchunk_raw(
fn get_bytes_from_key(
&mut self,
chunk_info: ChunkKey,
_: &mut Self::UserState,
) -> Result<Option<Vec<u8>>, Self::Err> {
Ok(self.db.get(&Self::build_key(&chunk_info)))
}

fn chunk_exists(
fn delete_bytes_at_key(
&mut self,
chunk_info: ChunkKey,
_: &mut Self::UserState,
) -> Result<bool, Self::Err> {
Ok(self.db.get(&Self::build_key(&chunk_info)).is_some())
) -> Result<(), Self::Err> {
Ok(self.db.delete(&Self::build_key(&chunk_info))?)
}

fn write_subchunk_batch(
Expand Down Expand Up @@ -182,14 +188,6 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
Ok(self.db.write(batch, false)?)
}

fn exist_chunk(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<(), Self::Err> {
Ok(self.set_subchunk_raw(chunk_info, &[], state)?)
}

fn build_key(key: &ChunkKey) -> Vec<u8> {
let mut key_bytes: Vec<u8> = vec![0; key.estimate_size()];
let mut buff: Cursor<&mut [u8]> = Cursor::new(&mut key_bytes);
Expand All @@ -211,6 +209,11 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
})
}

fn close(&mut self) -> Result<(), Self::Err> {
self.db.close()?;
Ok(())
}

fn generated_chunks(
&mut self,
_: &mut Self::UserState,
Expand Down
65 changes: 60 additions & 5 deletions crates/level/src/level/file_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,49 @@ pub trait RawWorldTrait: Sized {

type UserState;

fn set_subchunk_raw(
fn write_bytes_to_key(
&mut self,
chunk_info: ChunkKey,
chunk_bytes: &[u8],
state: &mut Self::UserState,
) -> Result<(), Self::Err>;

fn get_subchunk_raw(
fn get_bytes_from_key(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<Option<Vec<u8>>, Self::Err>;

fn delete_bytes_at_key(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<(), Self::Err>;

fn set_subchunk_raw(
&mut self,
chunk_info: ChunkKey,
chunk_bytes: &[u8],
state: &mut Self::UserState,
) -> Result<(), Self::Err> {
self.write_bytes_to_key(chunk_info, chunk_bytes, state)
}

fn get_subchunk_raw(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<Option<Vec<u8>>, Self::Err> {
self.get_bytes_from_key(chunk_info, state)
}

fn chunk_exists(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<bool, Self::Err>;
) -> Result<bool, Self::Err> {
Ok(self.get_bytes_from_key(chunk_info, state)?.is_some())
}

fn write_subchunk_batch(
&mut self,
Expand All @@ -65,11 +90,13 @@ pub trait RawWorldTrait: Sized {
state: &mut Self::UserState,
) -> Result<(), Self::Err>;

fn exist_chunk(
fn mark_exist_chunk(
&mut self,
chunk_info: ChunkKey,
state: &mut Self::UserState,
) -> Result<(), Self::Err>;
) -> Result<(), Self::Err> {
self.write_bytes_to_key(chunk_info, &[], state)
}

fn build_key(key: &ChunkKey) -> Vec<u8>;

Expand All @@ -79,8 +106,36 @@ pub trait RawWorldTrait: Sized {
state: &mut Self::UserState,
) -> Result<Self, Self::Err>;

fn close(&mut self) -> Result<(), Self::Err>;

fn generated_chunks(
&mut self,
state: &mut Self::UserState,
) -> Result<HashSet<(Dimension, Vec2<i32>)>, Self::Err>;

fn delete_chunk(
&mut self,
xz: Vec2<i32>,
dimension: Dimension,
subchunk_range: Vec2<i8>,
state: &mut Self::UserState,
) -> Result<(), Self::Err> {
for y in subchunk_range.x..=subchunk_range.y {
self.delete_subchunk(xz, dimension, y, state)?
}

self.delete_bytes_at_key(ChunkKey::chunk_marker(xz, dimension), state)?;

Ok(())
}

fn delete_subchunk(
&mut self,
xz: Vec2<i32>,
dimension: Dimension,
y: i8,
state: &mut Self::UserState,
) -> Result<(), Self::Err> {
self.delete_bytes_at_key(ChunkKey::new_subchunk(xz, dimension, y), state)
}
}
Loading
Loading