Skip to content

Commit

Permalink
docs: add documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
RubixDev committed May 8, 2024
1 parent e34a829 commit afc413a
Show file tree
Hide file tree
Showing 9 changed files with 281 additions and 34 deletions.
33 changes: 33 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ description = "A Rust library for reading, editing, and writing Minecraft litema
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
#! ## Features
default = ["chrono"]

## Use [`chrono`] types for timestamps.
chrono = ["dep:chrono"]

## Enable this when building the docs
docs = ["dep:document-features", "dep:rustc_version"]

[dependencies]
document-features = { version = "0.2.8", optional = true }
fastnbt = "2.5.0"
flate2 = "1.0.30"
mcdata = { version = "0.2.0", features = ["serde"] }
Expand All @@ -31,7 +37,11 @@ chrono = { version = "0.4.38", features = ["wasmbind"], optional = true }
js-sys = "0.3.69" # for current time without chrono feature

[dev-dependencies]
bounded-integer = "0.5.7"
mcdata = { version = "0.2.0", features = ["serde", "latest", "block-states"] }

[build-dependencies]
rustc_version = { version = "0.4.0", optional = true }

[package.metadata.docs.rs]
all-features = true
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,58 @@
[![Crates.io](https://img.shields.io/crates/v/rustmatica)](https://crates.io/crates/rustmatica)

A rust crate for working with Minecraft litematica files.

## Overview

The two main types of this crate are [`Litematic`] and [`Region`]. See their
documentation for more info.

The
[`examples` directory](https://github.com/RubixDev/rustmatica/tree/main/examples)
contains a few basic examples for how to use this crate.

## Usage with [`mcdata`]

`rustmatica` is tightly coupled with [`mcdata`] and makes use of its traits for
block states, entities, and block entities. By default, schematics will use
[`mcdata`]s "generic" types which store most of their data using
[`fastnbt::Value`]s.

```rust
use rustmatica::Litematic;
use mcdata::util::UVec3;

// type must be declared explicitly for Rust to use the default generics
let schem: Litematic = Litematic::read_file("test_files/axolotl.litematic")?;

// block has type `mcdata::GenericBlockState`
let block = schem.regions[0].get_block(UVec3::new(1, 0, 1));
assert_eq!(block.name, "minecraft:water");
// properties aren't typed
assert_eq!(block.properties["level"], "0");
# Ok::<(), rustmatica::Error>(())
```

But [`mcdata`] also offers more concrete types when enabling certain cargo
features. To use these, add a custom dependency on [`mcdata`] similar to this:

```toml
mcdata = { version = "<version>", features = ["latest", "block-states"] }
```

Then you can use the `mcdata::latest::BlockState` type instead:

```rust
use rustmatica::Litematic;
use mcdata::{util::UVec3, latest::BlockState};
use bounded_integer::BoundedU8;

let schem: Litematic<BlockState> = Litematic::read_file("test_files/axolotl.litematic")?;

// block has type `BlockState`
let block = schem.regions[0].get_block(UVec3::new(1, 0, 1));
assert_eq!(block, &BlockState::Water {
level: BoundedU8::new(0).unwrap(),
});
# Ok::<(), rustmatica::Error>(())
```
17 changes: 17 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#[cfg(not(feature = "docs"))]
fn main() {
println!("cargo:rerun-if-changed=build.rs");
}

#[cfg(feature = "docs")]
fn main() {
// for documenting features when using nightly
let channel = match rustc_version::version_meta().unwrap().channel {
rustc_version::Channel::Dev => "CHANNEL_DEV",
rustc_version::Channel::Nightly => "CHANNEL_NIGHTLY",
rustc_version::Channel::Beta => "CHANNEL_BETA",
rustc_version::Channel::Stable => "CHANNEL_STABLE",
};
println!("cargo:rustc-cfg={channel}");
println!("cargo:rerun-if-changed=build.rs");
}
1 change: 1 addition & 0 deletions dprint.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
},

"toml": {
"comment.forceLeadingSpace": false
},

"prettier": {
Expand Down
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/// A convenience type alias for [`Result`](std::result::Result) with the error variant as [`Error`].
pub type Result<T> = std::result::Result<T, Error>;

// TODO: this good?
/// The rustmatica error type.
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Any NBT error.
#[error(transparent)]
Nbt(#[from] fastnbt::error::Error),

/// Any IO error.
#[error(transparent)]
Io(#[from] std::io::Error),
}
8 changes: 7 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#![warn(rust_2018_idioms, missing_debug_implementations)]
#![doc = include_str!("../README.md")]
#![cfg_attr(
feature = "docs",
cfg_attr(doc, doc = ::document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#))
)]
#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))]
#![warn(rust_2018_idioms, missing_debug_implementations, missing_docs)]

mod error;
mod litematic;
Expand Down
46 changes: 44 additions & 2 deletions src/litematic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ const SCHEMATIC_VERSION: u32 = 6;

type CowStr = std::borrow::Cow<'static, str>;

/// A litematica schematic.
///
/// The type has three generic type parameters for the types of block states, entities, and block
/// entities. These types must implement the corresponding [`mcdata`] trait and default to
/// [`mcdata`]s "generic" types.
///
/// A litematica schematic consists of some metadata and a list of [`Region`]s. The metadata
/// contains information like the name, description, and author, while the [`Region`]s contain the
/// blocks and entities.
#[derive(Debug)]
pub struct Litematic<
BlockState = GenericBlockState,
Expand All @@ -30,19 +39,40 @@ pub struct Litematic<
Entity: mcdata::Entity + Serialize + DeserializeOwned,
BlockEntity: mcdata::BlockEntity + Serialize + DeserializeOwned,
{
/// The list of [`Region`]s for this schematic.
pub regions: Vec<Region<BlockState, Entity, BlockEntity>>,

/// The name of this schematic.
pub name: CowStr,

/// The description of this schematic.
pub description: CowStr,

/// The author of this schematic.
pub author: CowStr,

/// The schematic version.
pub version: u32,

/// The Minecraft [data version](https://minecraft.wiki/w/Data_version) used for blocks and
/// entities in this schematic.
///
/// See [`mcdata::data_version`] for a list of some important versions.
pub minecraft_data_version: u32,

/// The datetime of when this schematic was created.
#[cfg(feature = "chrono")]
pub time_created: DateTime<Utc>,

/// The unix timestamp of when this schematic was created.
#[cfg(not(feature = "chrono"))]
pub time_created: i64,

/// The datetime of when this schematic was last modified.
#[cfg(feature = "chrono")]
pub time_modified: DateTime<Utc>,

/// The unix timestamp of when this schematic was last modified.
#[cfg(not(feature = "chrono"))]
pub time_modified: i64,
}
Expand All @@ -53,6 +83,7 @@ where
Entity: mcdata::Entity + Serialize + DeserializeOwned,
BlockEntity: mcdata::BlockEntity + Serialize + DeserializeOwned,
{
/// Create a new, empty schematic with the given name, description, and author.
pub fn new(
name: impl Into<CowStr>,
description: impl Into<CowStr>,
Expand All @@ -71,7 +102,8 @@ where
}
}

pub fn from_raw(raw: schema::Litematic<BlockState, Entity, BlockEntity>) -> Self {
/// Construct a [`Litematic`] from a [raw NBT litematic](schema::Litematic).
pub(crate) fn from_raw(raw: schema::Litematic<BlockState, Entity, BlockEntity>) -> Self {
return Self {
regions: raw
.regions
Expand All @@ -97,7 +129,8 @@ where
};
}

pub fn to_raw(&self) -> schema::Litematic<BlockState, Entity, BlockEntity> {
/// Create a new [raw NBT litematic](schema::Litematic) from this [`Litematic`].
pub(crate) fn to_raw(&self) -> schema::Litematic<BlockState, Entity, BlockEntity> {
schema::Litematic {
regions: {
let mut map = HashMap::new();
Expand Down Expand Up @@ -129,21 +162,25 @@ where
}
}

/// Load a schematic from uncompressed bytes.
pub fn from_uncompressed_bytes(bytes: &[u8]) -> Result<Self> {
Ok(Self::from_raw(fastnbt::from_bytes(bytes)?))
}

/// Write this schematic to uncompressed bytes.
pub fn to_uncompressed_bytes(&self) -> Result<Vec<u8>> {
Ok(fastnbt::to_bytes(&self.to_raw())?)
}

/// Load a schematic from gzip compressed bytes.
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
let mut gz = GzDecoder::new(bytes);
let mut extracted = vec![];
gz.read_to_end(&mut extracted)?;
Self::from_uncompressed_bytes(&extracted)
}

/// Write this schematic to gzip compressed bytes.
pub fn to_bytes(&self) -> Result<Vec<u8>> {
let mut buf = vec![];
let mut gz = GzEncoder::new(&mut buf, Compression::default());
Expand All @@ -152,27 +189,32 @@ where
Ok(buf)
}

/// Load a schematic from a file.
pub fn read_file(filename: &str) -> Result<Self> {
let mut file = File::open(filename)?;
let mut bytes = vec![];
file.read_to_end(&mut bytes)?;
Litematic::from_bytes(&bytes)
}

/// Write this schematic to a file.
pub fn write_file(&self, filename: &str) -> Result<()> {
let mut file = File::create(filename)?;
file.write_all(&self.to_bytes()?)?;
Ok(())
}

/// The total number of blocks all regions combined contain.
pub fn total_blocks(&self) -> u64 {
self.regions.iter().map(|r| r.total_blocks() as u64).sum()
}

/// The total volume of all regions combined.
pub fn total_volume(&self) -> u32 {
self.regions.iter().map(|r| r.size.volume() as u32).sum()
}

/// The enclosing size of all regions.
pub fn enclosing_size(&self) -> UVec3 {
let mut bounds = [0; 6];
for region in self.regions.iter() {
Expand Down
Loading

0 comments on commit afc413a

Please sign in to comment.