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

Rework the level API again. #121

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions crates/level/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ vek = "0.17"
[dev-dependencies]
rand = "0.8"
copy_dir = "0.1.3"
anyhow = "1.0.95"


[[test]]
Expand Down
539 changes: 0 additions & 539 deletions crates/level/src/level/chunk.rs

This file was deleted.

27 changes: 0 additions & 27 deletions crates/level/src/level/chunk_cache.rs

This file was deleted.

16 changes: 8 additions & 8 deletions crates/level/src/level/db_interface/bedrock_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ use crate::level::db_interface::key_level::KeyTypeTag;
use bedrockrs_shared::world::dimension::Dimension;
use byteorder::{LittleEndian, WriteBytesExt};
use std::io::Cursor;
use vek::Vec2;
use vek::{Vec2, Vec3};

#[derive(Debug)]
pub struct ChunkKey {
xz: Vec2<i32>,
dim: Dimension,
key_type: KeyTypeTag,
y_index: Option<i8>,
pub xz: Vec2<i32>,
pub dim: Dimension,
pub key_type: KeyTypeTag,
pub y_index: Option<i8>,
}

impl ChunkKey {
pub fn new_subchunk(xz: Vec2<i32>, dim: Dimension, y_index: i8) -> Self {
pub fn new_sub_chunk(xyz: Vec3<i32>, dim: Dimension) -> Self {
Self {
xz,
xz: (xyz.x, xyz.z).into(),
dim,
key_type: KeyTypeTag::SubChunkPrefix,
y_index: Some(y_index),
y_index: Some(xyz.y as i8),
}
}

Expand Down
102 changes: 49 additions & 53 deletions crates/level/src/level/db_interface/rusty.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::level::db_interface::bedrock_key::ChunkKey;
use crate::level::db_interface::db::LevelDBKey;
use crate::level::db_interface::key_level::KeyTypeTag;
use crate::level::db_interface::key_level::KeyTypeTag::SubChunkPrefix;
use crate::level::file_interface::RawWorldTrait;
use bedrockrs_shared::world::dimension::Dimension;
use byteorder::{LittleEndian, ReadBytesExt};
Expand All @@ -10,7 +11,6 @@ use rusty_leveldb::compressor::NoneCompressor;
use rusty_leveldb::{Compressor, CompressorList, LdbIterator, Options, Status, WriteBatch, DB};
use std::collections::HashSet;
use std::io::Cursor;
use std::marker::PhantomData;
use std::path::Path;
use std::rc::Rc;
use thiserror::Error;
Expand Down Expand Up @@ -71,9 +71,8 @@ pub fn mcpe_options(compression_level: u8) -> Options {
}
const COMPRESSION_LEVEL: u8 = CompressionLevel::DefaultLevel as u8;

pub struct RustyDBInterface<UserState> {
db: DB,
phantom_data: PhantomData<UserState>,
pub struct RustyDBInterface {
pub db: DB,
}

#[derive(Debug, Error)]
Expand All @@ -82,9 +81,9 @@ pub enum DBError {
DatabaseError(#[from] Status),
}

impl<UserState> RustyDBInterface<UserState> {
fn build_key_batch(subchunk_batch_info: Vec<ChunkKey>, data: &mut Vec<u8>) -> WriteBatch {
let count = subchunk_batch_info
impl RustyDBInterface {
fn build_key_batch(sub_chunk_batch_info: Vec<ChunkKey>, data: &mut Vec<u8>) -> WriteBatch {
let count = sub_chunk_batch_info
.iter()
.map(|ele| ele.estimate_size())
.sum();
Expand All @@ -94,7 +93,7 @@ impl<UserState> RustyDBInterface<UserState> {

let mut batch = WriteBatch::default();

for key in subchunk_batch_info {
for key in sub_chunk_batch_info {
let start = buff.position();

key.write_key(&mut buff);
Expand All @@ -113,58 +112,76 @@ impl<UserState> RustyDBInterface<UserState> {
}
}

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

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

fn open(
path: Box<Path>,
create_if_missing: bool,
_: &mut Self::ConstructionInformation,
) -> Result<Self, Self::Err> {
let mut opts = mcpe_options(COMPRESSION_LEVEL);
opts.create_if_missing = create_if_missing;
let db = DB::open(path, opts)?;
Ok(Self { db })
}

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

fn flush(&mut self) -> Result<(), Self::Err> {
self.db.flush().map_err(|ele| Self::Err::DatabaseError(ele))
}

fn write_bytes_to_key(
&mut self,
chunk_info: ChunkKey,
chunk_bytes: &[u8],
_: &mut Self::UserState,
) -> Result<(), Self::Err> {
let mut batch = WriteBatch::default();
batch.put(&Self::build_key(&chunk_info), chunk_bytes);
Ok(self.db.write(batch, false)?)
}

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

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

fn set_sub_chunk_raw(
&mut self,
chunk_info: ChunkKey,
_: &mut Self::UserState,
chunk_bytes: &[u8],
) -> Result<(), Self::Err> {
Ok(self.db.delete(&Self::build_key(&chunk_info))?)
self.write_bytes_to_key(chunk_info, chunk_bytes)
}

fn write_subchunk_batch(
fn write_sub_chunk_batch(
&mut self,
subchunk_batch_info: Vec<(ChunkKey, Vec<u8>)>,
_: &mut Self::UserState,
sub_chunk_batch_info: Vec<(ChunkKey, Vec<u8>)>,
) -> Result<(), Self::Err> {
let mut data: Vec<u8> = vec![
0;
subchunk_batch_info
sub_chunk_batch_info
.iter()
.map(|(info, _)| info.estimate_size())
.sum()
];
let mut buff: Cursor<&mut [u8]> = Cursor::new(&mut data);
let mut batch = WriteBatch::default();
for (key, _) in &subchunk_batch_info {
for (key, _) in &sub_chunk_batch_info {
let start = buff.position();

key.write_key(&mut buff);
Expand All @@ -178,46 +195,24 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
Ok(self.db.write(batch, false)?)
}

fn write_subchunk_marker_batch(
fn write_sub_chunk_marker_batch(
&mut self,
subchunk_batch_info: Vec<ChunkKey>,
_: &mut Self::UserState,
sub_chunk_batch_info: Vec<ChunkKey>,
) -> Result<(), Self::Err> {
let mut data: Vec<u8> = Vec::new();
let batch = Self::build_key_batch(subchunk_batch_info, &mut data);
let batch = Self::build_key_batch(sub_chunk_batch_info, &mut data);
Ok(self.db.write(batch, false)?)
}

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);
key.write_key(&mut buff);
key_bytes
}

fn new(
path: Box<Path>,
create_if_missing: bool,
_: &mut Self::UserState,
) -> Result<Self, Self::Err> {
let mut opts = mcpe_options(COMPRESSION_LEVEL);
opts.create_if_missing = create_if_missing;
let db = DB::open(path, opts)?;
Ok(Self {
db,
phantom_data: PhantomData,
})
}

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

fn generated_chunks(
&mut self,
_: &mut Self::UserState,
) -> Result<HashSet<(Dimension, Vec2<i32>)>, Self::Err> {
fn generated_chunks(&mut self) -> Result<HashSet<(Dimension, Vec2<i32>)>, Self::Err> {
let mut out_set = HashSet::new();

let mut iter = self.db.new_iter()?;
Expand All @@ -228,7 +223,7 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {

iter.current(&mut key, data);
let len = key.len();
let mut cursor = Cursor::new(&mut key);
let mut cursor = Cursor::new(&key);

if len == 9 || len == 13 {
// Does a little hack to make sure it isn't reading a key that it doesn't want to
Expand All @@ -249,6 +244,7 @@ impl<UserState> RawWorldTrait for RustyDBInterface<UserState> {
} else {
Dimension::Overworld
};

out_set.insert((dim, (x, y).into()));
}
}
Expand Down
81 changes: 81 additions & 0 deletions crates/level/src/level/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use std::fmt::Debug;
use thiserror::Error;

#[derive(Debug, Error)]
pub enum SubChunkError {
#[error("Failed To Get Layer: {0}")]
LayerError(u8),
}

#[derive(Error, Debug)]
pub enum SubChunkSerDeError<WorldError: Debug, SerDeError: Debug> {
#[error(transparent)]
WorldError(WorldError),
#[error(transparent)]
SerDeError(SerDeError),
}

#[derive(Error, Debug)]
pub enum WholeLevelError<WorldError: Debug, SerDeError: Debug, TranslationError: Debug> {
#[error(transparent)]
TranslationError(TranslationError),
#[error(transparent)]
WorldError(WorldError),
#[error(transparent)]
SerDeError(SerDeError),
#[error(transparent)]
SubChunkError(#[from] SubChunkError),
}

#[derive(Error, Debug)]
pub enum WorldPipelineError<
WorldError: Debug,
Decode: Debug,
Encode: Debug,
TranslationError: Debug,
> {
#[error(transparent)]
TranslationError(TranslationError),
#[error(transparent)]
WorldError(WorldError),
#[error(transparent)]
DecodeError(Decode),
#[error(transparent)]
EncoderError(Encode),
#[error(transparent)]
SubChunkError(#[from] SubChunkError),
}

impl<WorldError: Debug, Decode: Debug, Encode: Debug, TranslationError: Debug>
WorldPipelineError<WorldError, Decode, Encode, TranslationError>
{
pub fn from_decode(other: WholeLevelError<WorldError, Decode, TranslationError>) -> Self {
match other {
WholeLevelError::TranslationError(r) => Self::TranslationError(r),
WholeLevelError::WorldError(r) => Self::WorldError(r),
WholeLevelError::SerDeError(r) => Self::DecodeError(r),
WholeLevelError::SubChunkError(r) => Self::SubChunkError(r),
}
}

pub fn from_encode(other: WholeLevelError<WorldError, Encode, TranslationError>) -> Self {
match other {
WholeLevelError::TranslationError(r) => Self::TranslationError(r),
WholeLevelError::WorldError(r) => Self::WorldError(r),
WholeLevelError::SerDeError(r) => Self::EncoderError(r),
WholeLevelError::SubChunkError(r) => Self::SubChunkError(r),
}
}
}

impl<WorldError: Debug, SerDeError: Debug, TranslationError: Debug>
From<SubChunkSerDeError<WorldError, SerDeError>>
for WholeLevelError<WorldError, SerDeError, TranslationError>
{
fn from(value: SubChunkSerDeError<WorldError, SerDeError>) -> Self {
match value {
SubChunkSerDeError::WorldError(e) => WholeLevelError::WorldError(e),
SubChunkSerDeError::SerDeError(e) => WholeLevelError::SerDeError(e),
}
}
}
Loading