diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index cef6a14..0000000 --- a/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -* -!/Cargo.* -!/src -!/crates diff --git a/.github/workflows/MinedMap.yml b/.github/workflows/MinedMap.yml deleted file mode 100644 index a0e58cf..0000000 --- a/.github/workflows/MinedMap.yml +++ /dev/null @@ -1,238 +0,0 @@ -name: 'MinedMap' -on: - push: - branches: - - 'main' - tags: - - 'v*' - pull_request: - branches: - - 'main' - workflow_dispatch: {} - -env: - RUSTFLAGS: -Dwarnings - RUSTDOCFLAGS: -Dwarnings - -jobs: - viewer: - runs-on: 'ubuntu-latest' - - steps: - - name: 'Checkout' - uses: 'actions/checkout@v4' - - - name: 'Get version' - id: 'tag' - run: | - set -o pipefail - git fetch --prune --unshallow --tags -f - echo "tag=$(git describe --abbrev=7 --match='v*' | sed 's/^v//')" >> $GITHUB_OUTPUT - - - name: 'Install' - run: | - pkgdir='build/pkg/MinedMap-${{ steps.tag.outputs.tag }}-viewer' - mkdir -p "$pkgdir" - cp -r viewer/* "$pkgdir"/ - rm "$pkgdir"/Dockerfile - - - name: 'Archive' - uses: 'actions/upload-artifact@v4' - with: - name: 'MinedMap-${{ steps.tag.outputs.tag }}-viewer' - path: 'build/pkg' - - fmt: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: '1.88' - components: rustfmt - - run: cargo fmt --all -- --check - - clippy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: '1.88' - components: clippy - - uses: swatinem/rust-cache@v2 - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --workspace --tests --examples - - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: '1.88' - components: rust-docs - - uses: swatinem/rust-cache@v2 - - run: cargo doc --workspace --no-deps --document-private-items - - test: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] - steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: '1.88' - - uses: swatinem/rust-cache@v2 - - run: cargo test --workspace - - run: cargo test --workspace --no-default-features - - run: cargo test --workspace --examples --bins - - run: cargo test --workspace --no-default-features --examples --bins - - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: 'macos-13' - target: 'aarch64-apple-darwin' - - os: 'macos-13' - target: 'x86_64-apple-darwin' - - os: 'windows-2019' - target: 'x86_64-pc-windows-msvc' - ext: '.exe' - - os: 'windows-2019' - target: 'i686-pc-windows-msvc' - ext: '.exe' - - os: 'ubuntu-22.04' - target: 'x86_64-unknown-linux-gnu' - - steps: - - name: 'Checkout' - uses: 'actions/checkout@v4' - - - name: 'Get version' - id: 'tag' - shell: 'bash' - run: | - set -o pipefail - git fetch --prune --unshallow --tags -f - echo "tag=$(git describe --abbrev=7 --match='v*' | sed 's/^v//')" >> $GITHUB_OUTPUT - - - uses: dtolnay/rust-toolchain@master - with: - toolchain: '1.88' - targets: '${{ matrix.target }}' - - - uses: swatinem/rust-cache@v2 - with: - key: '${{ matrix.target }}' - - - name: 'Build' - shell: 'bash' - env: - RUSTFLAGS: -Dwarnings -Cstrip=symbols - run: | - pkgdir='target/pkg/MinedMap-${{ steps.tag.outputs.tag }}-${{ matrix.target }}' - mkdir -p "$pkgdir" - cargo build --release --target=${{ matrix.target }} - cp target/${{ matrix.target }}/release/minedmap${{ matrix.ext }} "$pkgdir"/ - - - name: 'Archive' - uses: 'actions/upload-artifact@v4' - with: - name: 'MinedMap-${{ steps.tag.outputs.tag }}-${{ matrix.target }}' - path: 'target/pkg' - - build-container: - runs-on: ubuntu-latest - needs: - - test - steps: - - name: 'Checkout' - uses: 'actions/checkout@v4' - - - name: 'Get version' - id: 'tag' - run: | - set -o pipefail - git fetch --prune --unshallow --tags -f - echo "tag=$(git describe --abbrev=7 --match='v*' | sed 's/^v//')" >> $GITHUB_OUTPUT - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/neocturne/minedmap/minedmap - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=ref,event=branch - type=ref,event=branch,suffix=-{{sha}} - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - - name: Login to GHCR - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - uses: docker/setup-buildx-action@v3 - - - name: Build - uses: docker/build-push-action@v6 - with: - build-args: | - MINEDMAP_VERSION=${{ steps.tag.outputs.tag }} - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - viewer-container: - runs-on: ubuntu-latest - needs: - - test - steps: - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: | - ghcr.io/neocturne/minedmap/viewer - tags: | - type=raw,value=latest,enable={{is_default_branch}} - type=ref,event=branch - type=ref,event=branch,suffix=-{{sha}} - type=ref,event=pr - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - - name: Login to GHCR - if: github.event_name != 'pull_request' - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - uses: docker/setup-buildx-action@v3 - - - name: Build - uses: docker/build-push-action@v6 - with: - context: "{{defaultContext}}:viewer" - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitignore b/.gitignore index 73d8961..5e3deeb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ *~ /viewer/data -/resource/data -/resource/colors.json -/target +.idea/ +cmake-build-debug/ diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index f1f0234..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,210 +0,0 @@ - - -## [Unreleased] - ReleaseDate - -## [2.6.0] - 2025-06-30 - -### Added - -- Added support for Minecraft 1.21.5 to 1.21.7 - - Added new block types and handling for changed sign text storage format. - -## [2.5.0] - 2025-03-16 - -### Added - -- Added experimental watch mode - - Passing `--watch` will cause MinedMap to run continuously instead of exiting - after map generation, regenerating tiles whenever they change. - - `--watch-delay` can be used to configure the delay between detecting a change - and runing the map generation, also limiting how often the regeneration - happens. This defaults to `30s`; significantly smaller values probably don't - make sense because Minecraft writes out changes in batches anyways. - - Finally, `--jobs-initial` can be used to configure the number of parallel - generation threads for the initial cycle separately from the value used for - subsequent cycles after a change is detected (`-j`/`--jobs`). Subsequent - cycles usually need to regenerate only a small number of tiles, so setting - `--jobs` to a smaller value than `--jobs-initial` may be advantageous. - -- Added jemalloc support to fix performace on musl targets - - The global allocator can be switched to jemalloc by enabling the `jemalloc` - cargo feature now. This is not the default because it is not always faster - than the default system allocator; in particular, the glibc allocator has - slightly better performance in multithreaded mode. In addition, jemalloc - uses a bit more memory. - - In addition, the `jemalloc-auto` feature has been introduced, which is enabled - by default and sets the global allocator to jemalloc on platforms where it is - clearly advantageous. For now, this is only done on musl-based targets, as - musl's default allocator is very slow in multithreaded operation (which was - making higher thread counts like `-j8` basically useless due to 7-8x - slowdowns). With the new default, performance on musl is basically identical - to glibc. - - Note that some platforms like `msvc` are unsupported by jemalloc, and trying - to enable the `jemalloc` feature on these platforms may break the MinedMap - build or cause issues at runtime. -- Docker images can be downloaded from the GitHub Container registry - - Two images are provided, one for the tile renderer and one with the viewer - and a web server. A `docker-compose.yml` example can be found in the - repository as a starting point. - -### Changed - -- Unknown biome types (from not yet supported or modded versions of Minecraft) - will now use plains biome colors as a fallback instead of resulting in water, - grass and foliage blocks to be rendered as transparent pixels -- Switched from zlib-ng to zlib-rs - - This should have no noticable effect on the usage of MinedMap, but avoids - an external build dependency on CMake. -- Small (1-block) seagrass is now visible on the map - - 1-block seagrass in 1-block deep water would previously result in the ground - to be shown instead of water, as MinedMap currently doesn't handle the - "waterlogged" block status. As 1-block seagrass is relatively big compared to - other "small" plants, just considering it opaque seems like a good enough - solution that avoids having to implement advanced block status flags. -- Use Bincode 2 for storage of intermediate data - - The update from Bincode 1 to 2 slightly reduces the size of the `processed` - directory used for intermediate data. At least Rust 1.85 is now required to - build MinedMap. - -## [2.4.0] - 2025-01-11 - -### Added - -- Added support for rendering tiles in WebP format using the `--image-format` option - -## [2.3.1] - 2025-01-06 - -### Fixed - -- Fix text colors for signs modified using dye -- Fix text colors specified using `#rrggbb` CSS syntax in JSON text - -Only named colors specified via JSON text were working as intended. - -The mapping of color names to values is now handled by the generator. Both the generator and the -viewer must be updated for sign text colors to work. - -## [2.3.0] - 2025-01-02 - -### Added - -- Added support for Minecraft 1.21.4 block types -- Added support for Minecraft 1.21.4 Pale Garden biome -- viewer: added images for pale oak signs - -## [2.2.0] - 2024-06-23 - -### Added - -- Added support for Minecraft 1.21 block types - -## [2.1.1] - 2024-06-14 - -### Fixed - -- Fix crash due to incorrect counting in info message - - The calculation of the number of skipped regions could underflow when more invalid than valid - regions were encountered. -- Ignore empty region files instead of treating them as invalid - - Minecraft generates empty region files in some cases. Just ignore them instead of printing an - error message every time. - -## [2.1.0] - 2024-01-27 - -### Added - -- Added sign layer - - This feature is disabled by default. Use the `--sign-prefix` and `--sign-filter` options to - configure which signs to show on the map. `--sign-transform` allows to modify the displayed - sign text. - -### Changed - -- Without `--verbose`, only a single warning is printed at the end of - processing for unknown block/biome types, rather than once for every - section where such a block/biome is encountered. - -## [2.0.2] - 2024-01-07 - -### Added - -- Added support for Minecraft 1.20.3+ - - Minecraft 1.20.3 renamed the `grass` block type to `short_grass`. - -### Changed - -- Updated [Leaflet](https://leafletjs.com/) to 1.9.4 -- Updated attribution URL to https://github.com/neocturne/MinedMap - -## [2.0.1] - 2023-11-18 - -### Fixed - -- Proceed with missing tiles rather can failing completely when an invalid - region file is encountered and no processed data from a previous run exists - -## [2.0.0] - 2023-09-30 - -This is a complete rewrite of the map renderer in Rust, as the previous C++ -implementation was getting more and more difficult to maintain and keep current -versions of Minecraft supported. - -The new implementation is generally faster than the old one (by using better -data structures), but it also uses a bit more RAM and storage space for -intermediate data. - -### Added - -- Added support for Minecraft 1.20 biomes and block types -- Multithreading: Pass `-j N` to minedmap to use *N* CPU cores in parallel. Note - that this also multiplies the RAM requirements of MinedMap. -- Extended OS support: MinedMap should now run on every system supported by Rust - as a target. As I don't have a way to test these builds, binary releases are - still limited to Windows and Linux for now; on other targets, MinedMap must - be built from source. - -### Changed - -- Biome smoothing uses a different filter kernel now, which might result in - nicer gradients? -- Log messages have been reduced. Pass `-v` to get a message for each - processed file again. -- The intermediate data directory `biome` in the output directory has been - replaced with a new `processed` directory. The `biome` directory can be - deleted when reusing the output directory of an older MinedMap version. - -### Fixed - -- Warnings about unknown biomes or block types have been reduced to once per - chunk/section, so rending is not slowed down by these message so much anymore. - - Full support for custom biomes datapacks might be added in a future release. - - -[Unreleased]: https://github.com/neocturne/MinedMap/compare/v2.6.0...HEAD -[2.6.0]: https://github.com/neocturne/MinedMap/compare/v2.5.0...v2.6.0 -[2.5.0]: https://github.com/neocturne/MinedMap/compare/v2.4.0...v2.5.0 -[2.4.0]: https://github.com/neocturne/MinedMap/compare/v2.3.1...v2.4.0 -[2.3.1]: https://github.com/neocturne/MinedMap/compare/v2.3.0...v2.3.1 -[2.3.0]: https://github.com/neocturne/MinedMap/compare/v2.2.0...v2.3.0 -[2.2.0]: https://github.com/neocturne/MinedMap/compare/v2.1.1...v2.2.0 -[2.1.1]: https://github.com/neocturne/MinedMap/compare/v2.1.0...v2.1.1 -[2.1.0]: https://github.com/neocturne/MinedMap/compare/v2.0.2...v2.1.0 -[2.0.2]: https://github.com/neocturne/MinedMap/compare/v2.0.1...v2.0.2 -[2.0.1]: https://github.com/neocturne/MinedMap/compare/v2.0.0...v2.0.1 -[2.0.0]: https://github.com/neocturne/MinedMap/compare/v1.19.1...v2.0.0 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2cc6467 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8.4) +project(MINEDMAP CXX) + + +find_package(PNG REQUIRED) +find_package(ZLIB REQUIRED) + + +add_subdirectory(src) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 7718011..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,128 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -mschiffer@universe-factory.net. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index a000b9d..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,1568 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "anstream" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "bincode" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" -dependencies = [ - "bincode_derive", - "serde", - "unty", -] - -[[package]] -name = "bincode_derive" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" -dependencies = [ - "virtue", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bytemuck" -version = "1.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "cc" -version = "1.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "clap" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", - "terminal_size", -] - -[[package]] -name = "clap_derive" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "enum-map" -version = "2.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" -dependencies = [ - "enum-map-derive", -] - -[[package]] -name = "enum-map-derive" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "fastnbt" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d4a73a95dc65551ccd98e1ecd1adb5d1ba5361146963b31f481ca42fc0520a3" -dependencies = [ - "byteorder", - "cesu8", - "serde", - "serde_bytes", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "flate2" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" -dependencies = [ - "crc32fast", - "libz-rs-sys", - "miniz_oxide", -] - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-macro", - "futures-task", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "git-version" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" -dependencies = [ - "git-version-macro", -] - -[[package]] -name = "git-version-macro" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "glam" -version = "0.30.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50a99dbe56b72736564cfa4b85bf9a33079f16ae8b74983ab06af3b1a3696b11" - -[[package]] -name = "hashbrown" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - -[[package]] -name = "image" -version = "0.25.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "image-webp", - "num-traits", - "png", -] - -[[package]] -name = "image-webp" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6970fe7a5300b4b42e62c52efa0187540a5bef546c60edaf554ef595d2e6f0b" -dependencies = [ - "byteorder-lite", - "quick-error", -] - -[[package]] -name = "indexmap" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "inotify" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" -dependencies = [ - "bitflags 2.9.1", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom", - "libc", -] - -[[package]] -name = "kqueue" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "libredox" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" -dependencies = [ - "bitflags 2.9.1", - "libc", - "redox_syscall", -] - -[[package]] -name = "libz-rs-sys" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172a788537a2221661b480fee8dc5f96c580eb34fa88764d3205dc356c7e4221" -dependencies = [ - "zlib-rs", -] - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "lru" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0281c2e25e62316a5c9d98f2d2e9e95a37841afdaf4383c177dbb5c1dfab0568" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "minedmap" -version = "2.6.0" -dependencies = [ - "anyhow", - "bincode", - "clap", - "enum-map", - "fastnbt", - "flate2", - "futures-util", - "git-version", - "humantime", - "image", - "indexmap", - "lru", - "minedmap-default-alloc", - "minedmap-nbt", - "minedmap-resource", - "minedmap-types", - "notify", - "num-integer", - "num_cpus", - "phf", - "rayon", - "regex", - "rustc-hash", - "serde", - "serde_json", - "tokio", - "tracing", - "tracing-subscriber", - "zstd", -] - -[[package]] -name = "minedmap-default-alloc" -version = "0.1.0" -dependencies = [ - "tikv-jemallocator", -] - -[[package]] -name = "minedmap-nbt" -version = "0.2.0" -dependencies = [ - "anyhow", - "bytemuck", - "clap", - "fastnbt", - "flate2", - "minedmap-types", - "serde", -] - -[[package]] -name = "minedmap-resource" -version = "0.8.0" -dependencies = [ - "bincode", - "enumflags2", - "glam", -] - -[[package]] -name = "minedmap-types" -version = "0.2.0" -dependencies = [ - "bincode", - "itertools", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "log", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "notify" -version = "8.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" -dependencies = [ - "bitflags 2.9.1", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "log", - "mio", - "notify-types", - "walkdir", - "windows-sys 0.59.0", -] - -[[package]] -name = "notify-types" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "phf" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" -dependencies = [ - "phf_macros", - "phf_shared", - "serde", -] - -[[package]] -name = "phf_generator" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b" -dependencies = [ - "fastrand", - "phf_shared", -] - -[[package]] -name = "phf_macros" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_bytes" -version = "0.11.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "terminal_size" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" -dependencies = [ - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tikv-jemalloc-sys" -version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "tikv-jemallocator" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865" -dependencies = [ - "libc", - "tikv-jemalloc-sys", -] - -[[package]] -name = "tokio" -version = "1.45.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" -dependencies = [ - "backtrace", - "parking_lot", - "pin-project-lite", -] - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unty" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "virtue" -version = "0.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.2", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] - -[[package]] -name = "zlib-rs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index f0c2bc0..0000000 --- a/Cargo.toml +++ /dev/null @@ -1,73 +0,0 @@ -[workspace] -members = ["crates/*"] - -[workspace.package] -edition = "2024" -license = "MIT" -readme = "README.md" -repository = "https://github.com/neocturne/MinedMap" - -[workspace.metadata.release] -consolidate-commits = false -pre-release-commit-message = "{{crate_name}} {{version}}" - -[package] -name = "minedmap" -version = "2.6.0" -description = "Generate browsable maps from Minecraft save data" -edition.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true -exclude = [ - "/.github/", - "/docs/", - "/viewer/", - "/resource/", -] - -[package.metadata.release] -tag-message = "{{crate_name}} {{version}}" -pre-release-replacements = [ - {file="CHANGELOG.md", search="Unreleased", replace="{{version}}"}, - {file="CHANGELOG.md", search="\\.\\.\\.HEAD", replace="...{{tag_name}}", exactly=1}, - {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}"}, - {file="CHANGELOG.md", search="", replace="\n\n## [Unreleased] - ReleaseDate", exactly=1}, - {file="CHANGELOG.md", search="", replace="\n[Unreleased]: https://github.com/neocturne/MinedMap/compare/{{tag_name}}...HEAD", exactly=1}, -] - -[dependencies] -anyhow = "1.0.68" -bincode = "2.0.1" -clap = { version = "4.1.4", features = ["derive", "wrap_help"] } -enum-map = "2.7.3" -fastnbt = "2.3.2" -flate2 = { version = "1.1.0", features = ["zlib-rs"] } -futures-util = "0.3.28" -git-version = "0.3.5" -humantime = "2.1.0" -image = { version = "0.25.1", default-features = false, features = ["png", "webp"] } -indexmap = "2.0.0" -lru = "0.15.0" -minedmap-default-alloc = { version = "0.1.0", path = "crates/default-alloc", optional = true } -minedmap-nbt = { version = "0.2.0", path = "crates/nbt", default-features = false } -minedmap-resource = { version = "0.8.0", path = "crates/resource" } -minedmap-types = { version = "0.2.0", path = "crates/types" } -notify = "8.0.0" -num-integer = "0.1.45" -num_cpus = "1.16.0" -phf = { version = "0.12.1", features = ["macros"] } -rayon = "1.7.0" -regex = "1.10.2" -rustc-hash = "2.0.0" -serde = { version = "1.0.152", features = ["derive"] } -serde_json = "1.0.99" -tokio = { version = "1.31.0", features = ["rt", "parking_lot", "sync"] } -tracing = "0.1.37" -tracing-subscriber = "0.3.17" -zstd = "0.13.0" - -[features] -default = ["jemalloc-auto"] -jemalloc-auto = ["dep:minedmap-default-alloc"] -jemalloc = ["jemalloc-auto", "minedmap-default-alloc/jemalloc"] diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 4b9de31..0000000 --- a/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM docker.io/library/rust:1.88.0-alpine AS builder - -WORKDIR /build -RUN apk add --no-cache build-base tini-static - -ARG MINEDMAP_VERSION - -COPY . . -RUN cargo build -r -RUN strip target/release/minedmap - -FROM scratch - -COPY --from=builder /sbin/tini-static /build/target/release/minedmap /bin/ -ENTRYPOINT [ "/bin/tini-static", "--", "/bin/minedmap" ] - -USER 1000:1000 diff --git a/LICENSE b/LICENSE index 2f9ad3f..0372923 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,22 @@ -MIT License +Copyright (c) 2015-2019, Matthias Schiffer +All rights reserved. -Copyright (c) 2015 Matthias Schiffer +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index cd30c8b..a2c2daa 100644 --- a/README.md +++ b/README.md @@ -2,41 +2,33 @@ * Render beautiful maps of your [Minecraft](https://minecraft.net/) worlds! * Put them on a webserver and view them in your browser! -* Compatible with unmodified Minecraft Java Edition 1.8 up to 1.21.7 (no mod installation required!) +* Compatible with unmodified Minecraft Java Edition 1.8 up to 1.16 (no mod installation necessary!) * Illumination layer: the world at night -* Fast: create a full map for a huge 3GB savegame in less than 5 minutes in single-threaded operation -* Multi-threading support: pass `-j N` to the renderer to use `N` parallel threads for generation +* Fast: create a full map for a huge 3GB savegame in less than 5 minutes * Incremental updates: only recreate map tiles for regions that have changed -* Typically uses less than 100MB of RAM in single-threaded operation (may be higher when `-j` is passed) -* Cross-platform: runs on Linux, Windows, and likely other systems like MacOS as well +* Very low memory usage: typically uses less than 5MB of RAM -![Screenshot](https://raw.githubusercontent.com/neocturne/MinedMap/997a4fb24e89d2cd3c671d77eafaa47084d14304/docs/images/MinedMap.png) +![Screenshot](docs/images/MinedMap.png) -## About + +## How to use MinedMap consists of two components: a map renderer generating map tiles from Minecraft save games, and a viewer for displaying and navigating maps in a browser based on [Leaflet](https://leafletjs.com/). The map renderer is heavily inspired by -[MapRend](https://github.com/YSelfTool/MapRend), but has been reimplemented from scratch -(first in C++, now in Rust) for highest performance. +[MapRend](https://github.com/YSelfTool/MapRend), but it has been implemented in C++ +from scratch for highest performance. -## How to use - -Download the binary release that matches your platform from the Github release -page (or install from source using `cargo`), as well as the platform-independent -viewer archive. Extract the viewer archive. The extracted directory contains the -HTML and JavaScript to operate the viewer and will be made publicly accessible -on a web server. The image data generated by MinedMap will be stored in the -`data` subdirectory of the extracted viewer. - -Minecraft stores its save data in a directory `~/.minecraft/saves` on Linux, -and `C:\Users\\AppData\Roaming\.minecraft\saves`. To generate MinedMap -tile data from a save game called "World", use the a command like the following -(replacing the first argument with the path to your save data; `` refers -to the directory where you unpacked the MinedMap viewer): +The viewer expects the the map data in a directory named `data`. To generate a new +map, create this empty directory inside the viewer directory. Next, to generate the +map files run MinedMap passing the source and the destination paths on the command +line: ```shell -minedmap ~/.minecraft/saves/World /data +./MinedMap /path/to/save/game /path/to/viewer/data ``` +The save game is stored in `saves` inside your Minecraft main directory +(`~/.minecraft` on Linux, `C:\Users\\AppData\Roaming\.minecraft` on Windows) +in a subdirectory with the name of your world. The first map generation might take a while for big worlds, but subsequent calls will only rebuild tiles for region files that have changed, rarely taking more than a second @@ -45,8 +37,7 @@ MinedMap as a Cron job every minute. Note that it is not possible to open the viewer *index.html* without a webserver, as it cannot load the generated map information from `file://` URIs. For testing purposes, -you can use a minimal HTTP server, e.g. if you have Python installed just run the -following in the viewer directory: +you can use a minimal HTTP server, e.g. (if you have Python installed): ```shell python3 -m http.server ``` @@ -54,74 +45,27 @@ This test server is very slow and cannot handle multiple requests concurrently, a proper webserver like [nginx](https://nginx.org/) or upload the viewer together with the generated map files to public webspace to make the map available to others. -If you are uploading the directory to a remote webserver, you do not need to upload the -`/data/processed` directory, as it is only used locally to allow processing -updates more quickly. -### Image formats +## Building MinedMap -MinedMap renders map tiles as PNG by default. Pass `--image-format webp` to select -WebP instead. For typical Minecraft worlds, using WebP reduces file sizes by 20-25% -without increasing processing time. +Precompiled MinedMap binaries for Windows (32bit and 64bit versions) are available under +"Releases" on the Github page. On other platforms, MinedMap must be built from source. -MinedMap always uses lossless compression for tile images, regardless of the -image format. +MinedMap has been tested to work on Windows and Linux. I assume it can also be +built for MacOS and pretty much any POSIX-like system, but I didn't check. ¯\\\_(ツ)\_/¯ -### Signs +To build from source, you need Git, CMake, the GCC toolchain and the development +files for the libraries *zlib* and *libpng* (packages *git*, *cmake*, *build-essential*, +*zlib1g-dev* and *libpng-dev* on Debian/Ubuntu). -![Sign screenshot](https://raw.githubusercontent.com/neocturne/MinedMap/e5d9c813ba3118d04dc7e52e3dc6f48808a69120/docs/images/signs.png) - -MinedMap can display sign markers on the map, which will open a popup showing -the sign text when clicked. - -Generation of the sign layer is disabled by default. It can be enabled by passing -the `--sign-prefix` or `--sign-filter` options to MinedMap. The options allow -to configure which signs should be displayed, and they can be passed multiple -times to show every sign that matches at least one prefix or filter. - -`--sign-prefix` will make all signs visible the text of which starts with the -given prefix, so something like `--sign-prefix '[Map]'` would allow to put up -signs that start with "\[Map\]" in Minecraft to add markers to the map. An -empty prefix (`--sign-prefix ''`) can be used to make *all* signs visible on -the map. - -`--sign-filter` can be used for more advanced filters based on regular expressions. -`--sign-filter '\[Map\]'` would show all signs that contain "\[Map\]" -anywhere in their text, and `--sign-filter '.'` makes all non-empty signs (signs -containing at least one character) visible. See the documentation of the -[regex crate](https://docs.rs/regex) for more information on the supported syntax. - -All prefixes and filters are applied to the front and back text separately, but -both the front and the back text will be shown in the popup when one of them -matches. - -Finally, `--sign-transform` allows to specify sed-style replacement patterns to -modify the text displayed on the map. This can be used if the text matched by -`--sign-prefix` or `--sign-filter` should not be displayed: -`--sign-transform 's/\[Map\]//'` would replace each occurence of "\[Map\]" with -the empty string. - -**Note:** On Windows, double quotes (`"`) must be used for arguments instead -of single quotes (`'`), and all backslashes in the arguments must be escaped -by doubling them. This can make regular expressions somewhat difficult to -write and to read. - -## Installation - -Binary builds of the map generator for Linux and Windows, as well as an archive -containing the viewer can be found on the GitHub release page. - -Building the generator from source requires a recent Rust toolchain (1.72.0 -or newer). The following command can be used to build the current development version: +Use the following commands to build: ```shell -cargo install --git 'https://github.com/neocturne/MinedMap.git' +git clone https://github.com/NeoRaider/MinedMap.git # Or download a release ZIP and unpack it +mkdir MinedMap-build +cd MinedMap-build +cmake ../MinedMap -DCMAKE_BUILD_TYPE=RELEASE +make ``` - -If you are looking for the older C++ implementation of the MinedMap tile renderer, -see the [v1.19.1](https://github.com/neocturne/MinedMap/tree/v1.19.1) tag. - -## See also - -Other projects using MinedMap: - -- [minecraft\_map\_marker](https://github.com/christopher-besch/minecraft_map_marker) +After a successful build, the MinedMap renderer binary can be found in the *src* +subdirectory of the build dir `MinedMap-build`. The viewer is located in the cloned +Git repository `MinedMap`. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index c4c0668..0000000 --- a/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -# TODO - -## Optimizations - -- To check: - - Bulk `block_at()`, possibly other `top_layer()` improvements diff --git a/crates/default-alloc/Cargo.toml b/crates/default-alloc/Cargo.toml deleted file mode 100644 index b03a871..0000000 --- a/crates/default-alloc/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "minedmap-default-alloc" -version = "0.1.0" -description = "Helper crate for target-specific selection of global allocator default" -edition.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true - -[dependencies] -tikv-jemallocator = { version = "0.6.0", optional = true } - -[target.'cfg(target_env = "musl")'.dependencies] -tikv-jemallocator = "0.6.0" - -[features] -jemalloc = ["dep:tikv-jemallocator"] diff --git a/crates/default-alloc/src/lib.rs b/crates/default-alloc/src/lib.rs deleted file mode 100644 index 0797a5f..0000000 --- a/crates/default-alloc/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[cfg(any(target_env = "musl", feature = "jemalloc"))] -#[global_allocator] -static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; diff --git a/crates/nbt/Cargo.toml b/crates/nbt/Cargo.toml deleted file mode 100644 index 07a5fd7..0000000 --- a/crates/nbt/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "minedmap-nbt" -version = "0.2.0" -description = "MinedMap's handling of Minecraft NBT data and region files" -edition.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true - -[dependencies] -anyhow = "1.0.75" -bytemuck = "1.13.1" -fastnbt = "2.4.4" -flate2 = "1.1.0" -minedmap-types = { version = "0.2.0", path = "../types" } -serde = "1.0.183" - -[dev-dependencies] -clap = { version = "4.3.23", features = ["derive"] } -flate2 = { version = "1.1.0", features = ["zlib-rs"] } diff --git a/crates/nbt/examples/nbtdump.rs b/crates/nbt/examples/nbtdump.rs deleted file mode 100644 index 8b61693..0000000 --- a/crates/nbt/examples/nbtdump.rs +++ /dev/null @@ -1,26 +0,0 @@ -//! Dumps data from a NBT data file in a human-readable format - -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -use std::path::PathBuf; - -use anyhow::Result; -use clap::Parser; - -/// Dump a Minecraft NBT data file in a human-readable format -#[derive(Debug, Parser)] -#[command(version)] -struct Args { - /// Filename to dump - file: PathBuf, -} - -fn main() -> Result<()> { - let args = Args::parse(); - - let value: fastnbt::Value = minedmap_nbt::data::from_file(args.file.as_path())?; - println!("{value:#x?}"); - - Ok(()) -} diff --git a/crates/nbt/examples/regiondump.rs b/crates/nbt/examples/regiondump.rs deleted file mode 100644 index 7cece8c..0000000 --- a/crates/nbt/examples/regiondump.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! Dumps data from a region data file in a human-readable format - -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -use std::path::PathBuf; - -use anyhow::Result; -use clap::Parser; - -/// Dump a Minecraft NBT region file in a human-readable format -#[derive(Debug, Parser)] -#[command(version)] -struct Args { - /// Filename to dump - file: PathBuf, -} - -fn main() -> Result<()> { - let args = Args::parse(); - - minedmap_nbt::region::from_file(args.file.as_path())?.foreach_chunk( - |coords, value: fastnbt::Value| { - println!("Chunk {coords:?}: {value:#x?}"); - Ok(()) - }, - ) -} diff --git a/crates/nbt/src/data.rs b/crates/nbt/src/data.rs deleted file mode 100644 index bb2ac3b..0000000 --- a/crates/nbt/src/data.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Functions for reading and deserializing compressed NBT data - -use std::{fs::File, io::prelude::*, path::Path}; - -use anyhow::{Context, Result}; -use flate2::read::GzDecoder; -use serde::de::DeserializeOwned; - -/// Reads compressed NBT data from a reader and deserializes to a given data structure -pub fn from_reader(reader: R) -> Result -where - R: Read, - T: DeserializeOwned, -{ - let mut decoder = GzDecoder::new(reader); - let mut buf = vec![]; - decoder - .read_to_end(&mut buf) - .context("Failed to read file")?; - - fastnbt::from_bytes(&buf).context("Failed to decode NBT data") -} - -/// Reads compressed NBT data from a file and deserializes to a given data structure -pub fn from_file(path: P) -> Result -where - P: AsRef, - T: DeserializeOwned, -{ - let file = File::open(path).context("Failed to open file")?; - from_reader(file) -} diff --git a/crates/nbt/src/lib.rs b/crates/nbt/src/lib.rs deleted file mode 100644 index 98e6d1b..0000000 --- a/crates/nbt/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![doc = env!("CARGO_PKG_DESCRIPTION")] -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -pub mod data; -pub mod region; diff --git a/crates/nbt/src/region.rs b/crates/nbt/src/region.rs deleted file mode 100644 index 6a79a39..0000000 --- a/crates/nbt/src/region.rs +++ /dev/null @@ -1,162 +0,0 @@ -//! Functions for reading and deserializing region data - -use std::{ - fs::File, - io::{SeekFrom, prelude::*}, - path::Path, -}; - -use anyhow::{Context, Result, bail}; -use flate2::read::ZlibDecoder; -use serde::de::DeserializeOwned; - -use minedmap_types::*; - -/// Data block size of region data files -/// -/// After one header block, the region file consists of one or more consecutive blocks -/// of data for each populated chunk. -const BLOCKSIZE: usize = 4096; - -/// Chunk descriptor extracted from region file header -#[derive(Debug)] -struct ChunkDesc { - /// Offset of data block where the chunk starts - offset: u32, - /// Number of data block used by the chunk - len: u8, - /// Coodinates of chunk described by this descriptor - coords: ChunkCoords, -} - -/// Parses the header of a region data file -fn parse_header(header: &ChunkArray) -> Vec { - let mut chunks: Vec<_> = header - .iter() - .filter_map(|(coords, &chunk)| { - let offset_len = u32::from_be(chunk); - - let offset = offset_len >> 8; - let len = offset_len as u8; - - if offset == 0 || len == 0 { - return None; - } - - Some(ChunkDesc { - offset, - len, - coords, - }) - }) - .collect(); - - chunks.sort_by_key(|chunk| chunk.offset); - - chunks -} - -/// Decompresses chunk data and deserializes to a given data structure -fn decode_chunk(buf: &[u8]) -> Result -where - T: DeserializeOwned, -{ - let (format, buf) = buf.split_at(1); - if format[0] != 2 { - bail!("Unknown chunk format"); - } - - let mut decoder = ZlibDecoder::new(buf); - let mut decode_buffer = vec![]; - decoder - .read_to_end(&mut decode_buffer) - .context("Failed to decompress chunk data")?; - - fastnbt::from_bytes(&decode_buffer).context("Failed to decode NBT data") -} - -/// Wraps a reader used to read a region data file -#[derive(Debug)] -pub struct Region { - /// The wrapper reader - reader: R, -} - -impl Region { - /// Iterates over the chunks of the region data - /// - /// The order of iteration is based on the order the chunks appear in the - /// data file. - pub fn foreach_chunk(self, mut f: F) -> Result<()> - where - R: Read + Seek, - T: DeserializeOwned, - F: FnMut(ChunkCoords, T) -> Result<()>, - { - let Region { mut reader } = self; - - let chunks = { - let mut header = ChunkArray::::default(); - reader - .read_exact(bytemuck::cast_mut::<_, [u8; BLOCKSIZE]>(&mut header.0)) - .context("Failed to read region header")?; - - parse_header(&header) - }; - - let mut seen = ChunkArray::::default(); - - for ChunkDesc { - offset, - len, - coords, - } in chunks - { - if seen[coords] { - bail!("Duplicate chunk {:?}", coords); - } - seen[coords] = true; - - reader - .seek(SeekFrom::Start(offset as u64 * BLOCKSIZE as u64)) - .context("Failed to seek chunk data")?; - - let mut len_buf = [0u8; 4]; - reader - .read_exact(&mut len_buf) - .with_context(|| format!("Failed to read length for chunk {coords:?}"))?; - let byte_len = u32::from_be_bytes(len_buf) as usize; - if byte_len < 1 || byte_len > (len as usize) * BLOCKSIZE - 4 { - bail!("Invalid length for chunk {:?}", coords); - } - - let mut buffer = vec![0; byte_len]; - reader - .read_exact(&mut buffer) - .with_context(|| format!("Failed to read data for chunk {coords:?}"))?; - let chunk = decode_chunk(&buffer) - .with_context(|| format!("Failed to decode data for chunk {coords:?}"))?; - - f(coords, chunk)?; - } - - Ok(()) - } -} - -/// Creates a new [Region] from a reader -pub fn from_reader(reader: R) -> Region -where - R: Read + Seek, -{ - Region { reader } -} - -/// Creates a new [Region] for a file -pub fn from_file

(path: P) -> Result> -where - P: AsRef, -{ - let file = File::open(path).context("Failed to open file")?; - Ok(from_reader(file)) -} diff --git a/crates/resource/Cargo.toml b/crates/resource/Cargo.toml deleted file mode 100644 index b59492c..0000000 --- a/crates/resource/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "minedmap-resource" -version = "0.8.0" -description = "Data describing Minecraft biomes and block types" -edition.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true - -[dependencies] -bincode = "2.0.1" -enumflags2 = "0.7.7" -glam = "0.30.0" diff --git a/crates/resource/src/biomes.rs b/crates/resource/src/biomes.rs deleted file mode 100644 index 55c5e74..0000000 --- a/crates/resource/src/biomes.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Biome data -//! -//! This file is generated using resource/biomes.py, do not edit - -use super::*; -use BiomeGrassColorModifier::*; - -/// List if known biomes and their properties -pub const BIOMES: &[(&str, Biome)] = &[ - ( - "badlands", - Biome::new(200, 0) - .foliage([158, 129, 77]) - .grass([144, 129, 77]), - ), - ("bamboo_jungle", Biome::new(95, 90)), - ("basalt_deltas", Biome::new(200, 0)), - ("beach", Biome::new(80, 40)), - ("birch_forest", Biome::new(60, 60)), - ( - "cherry_grove", - Biome::new(50, 80) - .foliage([182, 219, 97]) - .grass([182, 219, 97]) - .water([93, 183, 239]), - ), - ("cold_ocean", Biome::new(50, 50).water([61, 87, 214])), - ("crimson_forest", Biome::new(200, 0)), - ("dark_forest", Biome::new(70, 80).modify(DarkForest)), - ("deep_cold_ocean", Biome::new(50, 50).water([61, 87, 214])), - ("deep_dark", Biome::new(80, 40)), - ("deep_frozen_ocean", Biome::new(50, 50).water([57, 56, 201])), - ( - "deep_lukewarm_ocean", - Biome::new(50, 50).water([69, 173, 242]), - ), - ("deep_ocean", Biome::new(50, 50)), - ("desert", Biome::new(200, 0)), - ("dripstone_caves", Biome::new(80, 40)), - ("end_barrens", Biome::new(50, 50)), - ("end_highlands", Biome::new(50, 50)), - ("end_midlands", Biome::new(50, 50)), - ( - "eroded_badlands", - Biome::new(200, 0) - .foliage([158, 129, 77]) - .grass([144, 129, 77]), - ), - ("flower_forest", Biome::new(70, 80)), - ("forest", Biome::new(70, 80)), - ("frozen_ocean", Biome::new(0, 50).water([57, 56, 201])), - ("frozen_peaks", Biome::new(-70, 90)), - ("frozen_river", Biome::new(0, 50).water([57, 56, 201])), - ("grove", Biome::new(-20, 80)), - ("ice_spikes", Biome::new(0, 50)), - ("jagged_peaks", Biome::new(-70, 90)), - ("jungle", Biome::new(95, 90)), - ("lukewarm_ocean", Biome::new(50, 50).water([69, 173, 242])), - ("lush_caves", Biome::new(50, 50)), - ( - "mangrove_swamp", - Biome::new(80, 90) - .foliage([141, 177, 39]) - .modify(Swamp) - .water([58, 122, 106]), - ), - ("meadow", Biome::new(50, 80).water([14, 78, 207])), - ("mushroom_fields", Biome::new(90, 100)), - ("nether_wastes", Biome::new(200, 0)), - ("ocean", Biome::new(50, 50)), - ("old_growth_birch_forest", Biome::new(60, 60)), - ("old_growth_pine_taiga", Biome::new(30, 80)), - ("old_growth_spruce_taiga", Biome::new(25, 80)), - ( - "pale_garden", - Biome::new(70, 80) - .foliage([135, 141, 118]) - .grass([119, 130, 114]) - .water([118, 136, 157]), - ), - ("plains", Biome::new(80, 40)), - ("river", Biome::new(50, 50)), - ("savanna", Biome::new(200, 0)), - ("savanna_plateau", Biome::new(200, 0)), - ("small_end_islands", Biome::new(50, 50)), - ("snowy_beach", Biome::new(5, 30).water([61, 87, 214])), - ("snowy_plains", Biome::new(0, 50)), - ("snowy_slopes", Biome::new(-30, 90)), - ("snowy_taiga", Biome::new(-50, 40).water([61, 87, 214])), - ("soul_sand_valley", Biome::new(200, 0)), - ("sparse_jungle", Biome::new(95, 80)), - ("stony_peaks", Biome::new(100, 30)), - ("stony_shore", Biome::new(20, 30)), - ("sunflower_plains", Biome::new(80, 40)), - ( - "swamp", - Biome::new(80, 90) - .foliage([106, 112, 57]) - .modify(Swamp) - .water([97, 123, 100]), - ), - ("taiga", Biome::new(25, 80)), - ("the_end", Biome::new(50, 50)), - ("the_void", Biome::new(50, 50)), - ("warm_ocean", Biome::new(50, 50).water([67, 213, 238])), - ("warped_forest", Biome::new(200, 0)), - ("windswept_forest", Biome::new(20, 30)), - ("windswept_gravelly_hills", Biome::new(20, 30)), - ("windswept_hills", Biome::new(20, 30)), - ("windswept_savanna", Biome::new(200, 0)), - ( - "wooded_badlands", - Biome::new(200, 0) - .foliage([158, 129, 77]) - .grass([144, 129, 77]), - ), -]; diff --git a/crates/resource/src/block_color.rs b/crates/resource/src/block_color.rs deleted file mode 100644 index e95e0ed..0000000 --- a/crates/resource/src/block_color.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! Functions for computations of block colors - -use super::{Biome, BlockColor, Color, Colorf}; - -/// Converts an u8 RGB color to a float vector -fn color_vec_unscaled(color: Color) -> Colorf { - Colorf::from_array(color.0.map(f32::from)) -} - -/// Converts an u8 RGB color to a float vector, scaling the components to 0.0..1.0 -fn color_vec(color: Color) -> Colorf { - color_vec_unscaled(color) / 255.0 -} - -/// Helper for grass and foliage colors -/// -/// Biome temperature and downfall are modified based on the depth value -/// before using them to compute the final color -fn color_from_params(colors: &[Colorf; 3], biome: &Biome, depth: f32) -> Colorf { - let temp = (biome.temp() - f32::max((depth - 64.0) / 600.0, 0.0)).clamp(0.0, 1.0); - let downfall = biome.downfall().clamp(0.0, 1.0) * temp; - - colors[0] + temp * colors[1] + downfall * colors[2] -} - -/// Extension trait with helpers for computing biome-specific block colors -trait BiomeExt { - /// Returns the grass color of the biome at a given depth - fn grass_color(&self, depth: f32) -> Colorf; - /// Returns the foliage color of the biome at a given depth - fn foliage_color(&self, depth: f32) -> Colorf; - /// Returns the water color of the biome - fn water_color(&self) -> Colorf; -} - -impl BiomeExt for Biome { - fn grass_color(&self, depth: f32) -> Colorf { - use super::BiomeGrassColorModifier::*; - - /// Color matrix extracted from grass color texture - const GRASS_COLORS: [Colorf; 3] = [ - Colorf::new(0.502, 0.706, 0.592), // lower right - Colorf::new(0.247, 0.012, -0.259), // lower left - lower right - Colorf::new(-0.471, 0.086, -0.133), // upper left - lower left - ]; - /// Used for dark forst grass color modifier - const DARK_FOREST_GRASS_COLOR: Colorf = Colorf::new(0.157, 0.204, 0.039); // == color_vec(Color([40, 52, 10])) - /// Grass color in swamp biomes - const SWAMP_GRASS_COLOR: Colorf = Colorf::new(0.416, 0.439, 0.224); // == color_vec(Color([106, 112, 57])) - - let regular_color = || { - self.grass_color - .map(color_vec) - .unwrap_or_else(|| color_from_params(&GRASS_COLORS, self, depth)) - }; - - match self.grass_color_modifier { - Some(DarkForest) => 0.5 * (regular_color() + DARK_FOREST_GRASS_COLOR), - Some(Swamp) => SWAMP_GRASS_COLOR, - None => regular_color(), - } - } - - fn foliage_color(&self, depth: f32) -> Colorf { - /// Color matrix extracted from foliage color texture - const FOLIAGE_COLORS: [Colorf; 3] = [ - Colorf::new(0.376, 0.631, 0.482), // lower right - Colorf::new(0.306, 0.012, -0.317), // lower left - lower right - Colorf::new(-0.580, 0.106, -0.165), // upper left - lower left - ]; - - self.foliage_color - .map(color_vec) - .unwrap_or_else(|| color_from_params(&FOLIAGE_COLORS, self, depth)) - } - - fn water_color(&self) -> Colorf { - /// Default biome water color - /// - /// Used for biomes that don't explicitly set a water color - const DEFAULT_WATER_COLOR: Colorf = Colorf::new(0.247, 0.463, 0.894); // == color_vec(Color([63, 118, 228])) - - self.water_color - .map(color_vec) - .unwrap_or(DEFAULT_WATER_COLOR) - } -} - -/// Color multiplier for birch leaves -const BIRCH_COLOR: Colorf = Colorf::new(0.502, 0.655, 0.333); // == color_vec(Color([128, 167, 85])) -/// Color multiplier for spruce leaves -const EVERGREEN_COLOR: Colorf = Colorf::new(0.380, 0.600, 0.380); // == color_vec(Color([97, 153, 97])) - -/// Determined if calling [block_color] for a given [BlockColor] needs biome information -pub fn needs_biome(block: BlockColor) -> bool { - use super::BlockFlag::*; - - block.is(Grass) || block.is(Foliage) || block.is(Water) -} - -/// Determined the block color to display for a given [BlockColor] -/// -/// [needs_biome] must be used to determine whether passing a [Biome] is necessary. -/// Will panic if a [Biome] is necessary, but none is passed. -pub fn block_color(block: BlockColor, biome: Option<&Biome>, depth: f32) -> Colorf { - use super::BlockFlag::*; - - let get_biome = || biome.expect("needs biome to determine block color"); - - let mut color = color_vec_unscaled(block.color); - - if block.is(Grass) { - color *= get_biome().grass_color(depth); - } - if block.is(Foliage) { - color *= get_biome().foliage_color(depth); - } - if block.is(Birch) { - color *= BIRCH_COLOR; - } - if block.is(Spruce) { - color *= EVERGREEN_COLOR; - } - if block.is(Water) { - color *= get_biome().water_color(); - } - - color * (0.5 + 0.005 * depth) -} diff --git a/crates/resource/src/block_types.rs b/crates/resource/src/block_types.rs deleted file mode 100644 index 9419690..0000000 --- a/crates/resource/src/block_types.rs +++ /dev/null @@ -1,11121 +0,0 @@ -//! Block type information -//! -//! This file is generated using resource/generate.py, do not edit - -use enumflags2::make_bitflags; - -use super::*; - -/// List if known block types and their properties -pub const BLOCK_TYPES: &[(&str, ConstBlockType)] = &[ - ( - "acacia_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "acacia_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([167, 95, 60]), - }, - sign_material: None, - }, - ), - ( - "acacia_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("acacia"), - }, - ), - ( - "acacia_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Foliage}), - color: Color([149, 148, 148]), - }, - sign_material: None, - }, - ), - ( - "acacia_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([150, 88, 55]), - }, - sign_material: None, - }, - ), - ( - "acacia_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([118, 117, 23]), - }, - sign_material: None, - }, - ), - ( - "acacia_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("acacia"), - }, - ), - ( - "acacia_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 90, 50]), - }, - sign_material: None, - }, - ), - ( - "acacia_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([156, 87, 51]), - }, - sign_material: None, - }, - ), - ( - "acacia_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("acacia"), - }, - ), - ( - "acacia_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("acacia"), - }, - ), - ( - "acacia_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 96, 86]), - }, - sign_material: None, - }, - ), - ( - "activator_rail", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 87, 74]), - }, - sign_material: None, - }, - ), - ( - "air", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "allium", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "amethyst_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([133, 97, 191]), - }, - sign_material: None, - }, - ), - ( - "amethyst_cluster", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([163, 126, 207]), - }, - sign_material: None, - }, - ), - ( - "ancient_debris", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([94, 66, 58]), - }, - sign_material: None, - }, - ), - ( - "andesite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 136, 136]), - }, - sign_material: None, - }, - ), - ( - "andesite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 136, 136]), - }, - sign_material: None, - }, - ), - ( - "andesite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 136, 136]), - }, - sign_material: None, - }, - ), - ( - "andesite_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 136, 136]), - }, - sign_material: None, - }, - ), - ( - "anvil", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 72]), - }, - sign_material: None, - }, - ), - ( - "attached_melon_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([141, 142, 141]), - }, - sign_material: None, - }, - ), - ( - "attached_pumpkin_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([139, 139, 139]), - }, - sign_material: None, - }, - ), - ( - "azalea", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 124, 47]), - }, - sign_material: None, - }, - ), - ( - "azalea_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([90, 114, 44]), - }, - sign_material: None, - }, - ), - ( - "azure_bluet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "bamboo", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 144, 19]), - }, - sign_material: None, - }, - ), - ( - "bamboo_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([139, 141, 62]), - }, - sign_material: None, - }, - ), - ( - "bamboo_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "bamboo_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 171, 81]), - }, - sign_material: None, - }, - ), - ( - "bamboo_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("bamboo"), - }, - ), - ( - "bamboo_mosaic", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 170, 78]), - }, - sign_material: None, - }, - ), - ( - "bamboo_mosaic_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 170, 78]), - }, - sign_material: None, - }, - ), - ( - "bamboo_mosaic_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 170, 78]), - }, - sign_material: None, - }, - ), - ( - "bamboo_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "bamboo_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("bamboo"), - }, - ), - ( - "bamboo_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 173, 80]), - }, - sign_material: None, - }, - ), - ( - "bamboo_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([198, 179, 85]), - }, - sign_material: None, - }, - ), - ( - "bamboo_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("bamboo"), - }, - ), - ( - "bamboo_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("bamboo"), - }, - ), - ( - "barrel", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([134, 100, 58]), - }, - sign_material: None, - }, - ), - ( - "barrier", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "basalt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 81, 86]), - }, - sign_material: None, - }, - ), - ( - "beacon", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 220, 215]), - }, - sign_material: None, - }, - ), - ( - "bedrock", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([85, 85, 85]), - }, - sign_material: None, - }, - ), - ( - "bee_nest", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([202, 160, 74]), - }, - sign_material: None, - }, - ), - ( - "beehive", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([180, 146, 90]), - }, - sign_material: None, - }, - ), - ( - "beetroots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 91, 30]), - }, - sign_material: None, - }, - ), - ( - "bell", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([253, 235, 110]), - }, - sign_material: None, - }, - ), - ( - "big_dripleaf", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([111, 141, 51]), - }, - sign_material: None, - }, - ), - ( - "big_dripleaf_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "birch_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "birch_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([220, 209, 176]), - }, - sign_material: None, - }, - ), - ( - "birch_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("birch"), - }, - ), - ( - "birch_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Birch}), - color: Color([130, 129, 130]), - }, - sign_material: None, - }, - ), - ( - "birch_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 179, 135]), - }, - sign_material: None, - }, - ), - ( - "birch_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 160, 79]), - }, - sign_material: None, - }, - ), - ( - "birch_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("birch"), - }, - ), - ( - "birch_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 175, 121]), - }, - sign_material: None, - }, - ), - ( - "birch_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([207, 194, 157]), - }, - sign_material: None, - }, - ), - ( - "birch_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("birch"), - }, - ), - ( - "birch_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("birch"), - }, - ), - ( - "birch_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([216, 215, 210]), - }, - sign_material: None, - }, - ), - ( - "black_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "black_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "black_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "black_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "black_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 21, 25]), - }, - sign_material: None, - }, - ), - ( - "black_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([8, 10, 15]), - }, - sign_material: None, - }, - ), - ( - "black_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([25, 26, 31]), - }, - sign_material: None, - }, - ), - ( - "black_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([67, 30, 32]), - }, - sign_material: None, - }, - ), - ( - "black_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([25, 25, 29]), - }, - sign_material: None, - }, - ), - ( - "black_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([25, 25, 25]), - }, - sign_material: None, - }, - ), - ( - "black_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([24, 24, 24]), - }, - sign_material: None, - }, - ), - ( - "black_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([37, 22, 16]), - }, - sign_material: None, - }, - ), - ( - "black_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "black_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 21, 25]), - }, - sign_material: None, - }, - ), - ( - "blackstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([42, 36, 41]), - }, - sign_material: None, - }, - ), - ( - "blackstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([42, 36, 41]), - }, - sign_material: None, - }, - ), - ( - "blackstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([42, 36, 41]), - }, - sign_material: None, - }, - ), - ( - "blackstone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([42, 36, 41]), - }, - sign_material: None, - }, - ), - ( - "blast_furnace", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 80, 81]), - }, - sign_material: None, - }, - ), - ( - "blue_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "blue_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "blue_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "blue_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "blue_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 57, 157]), - }, - sign_material: None, - }, - ), - ( - "blue_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 46, 143]), - }, - sign_material: None, - }, - ), - ( - "blue_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 73, 166]), - }, - sign_material: None, - }, - ), - ( - "blue_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([47, 64, 139]), - }, - sign_material: None, - }, - ), - ( - "blue_ice", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([116, 167, 253]), - }, - sign_material: None, - }, - ), - ( - "blue_orchid", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "blue_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 45, 140]), - }, - sign_material: None, - }, - ), - ( - "blue_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([51, 76, 178]), - }, - sign_material: None, - }, - ), - ( - "blue_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([48, 73, 171]), - }, - sign_material: None, - }, - ), - ( - "blue_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([74, 59, 91]), - }, - sign_material: None, - }, - ), - ( - "blue_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "blue_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 57, 157]), - }, - sign_material: None, - }, - ), - ( - "bone_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([209, 206, 179]), - }, - sign_material: None, - }, - ), - ( - "bookshelf", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "brain_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brain_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([207, 91, 159]), - }, - sign_material: None, - }, - ), - ( - "brain_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brain_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brewing_stand", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 100, 80]), - }, - sign_material: None, - }, - ), - ( - "brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([150, 97, 83]), - }, - sign_material: None, - }, - ), - ( - "brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([150, 97, 83]), - }, - sign_material: None, - }, - ), - ( - "brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([150, 97, 83]), - }, - sign_material: None, - }, - ), - ( - "bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([150, 97, 83]), - }, - sign_material: None, - }, - ), - ( - "brown_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brown_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brown_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brown_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "brown_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 71, 40]), - }, - sign_material: None, - }, - ), - ( - "brown_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([96, 59, 31]), - }, - sign_material: None, - }, - ), - ( - "brown_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 84, 53]), - }, - sign_material: None, - }, - ), - ( - "brown_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 106, 85]), - }, - sign_material: None, - }, - ), - ( - "brown_mushroom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brown_mushroom_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 111, 81]), - }, - sign_material: None, - }, - ), - ( - "brown_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 66, 35]), - }, - sign_material: None, - }, - ), - ( - "brown_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([102, 76, 51]), - }, - sign_material: None, - }, - ), - ( - "brown_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 73, 48]), - }, - sign_material: None, - }, - ), - ( - "brown_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 51, 35]), - }, - sign_material: None, - }, - ), - ( - "brown_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "brown_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 71, 40]), - }, - sign_material: None, - }, - ), - ( - "bubble_column", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Water}), - color: Color([177, 177, 177]), - }, - sign_material: None, - }, - ), - ( - "bubble_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "bubble_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([165, 26, 162]), - }, - sign_material: None, - }, - ), - ( - "bubble_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "bubble_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "budding_amethyst", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([132, 96, 186]), - }, - sign_material: None, - }, - ), - ( - "bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([119, 120, 119]), - }, - sign_material: None, - }, - ), - ( - "cactus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([85, 127, 43]), - }, - sign_material: None, - }, - ), - ( - "cactus_flower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([209, 120, 135]), - }, - sign_material: None, - }, - ), - ( - "cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "calcite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 224, 220]), - }, - sign_material: None, - }, - ), - ( - "calibrated_sculk_sensor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([27, 79, 100]), - }, - sign_material: None, - }, - ), - ( - "campfire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 88, 54]), - }, - sign_material: None, - }, - ), - ( - "candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "carrots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([81, 124, 37]), - }, - sign_material: None, - }, - ), - ( - "cartography_table", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 87, 67]), - }, - sign_material: None, - }, - ), - ( - "carved_pumpkin", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([198, 118, 24]), - }, - sign_material: None, - }, - ), - ( - "cauldron", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 72, 74]), - }, - sign_material: None, - }, - ), - ( - "cave_air", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cave_vines", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([90, 109, 40]), - }, - sign_material: None, - }, - ), - ( - "cave_vines_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([88, 101, 38]), - }, - sign_material: None, - }, - ), - ( - "chain", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "chain_command_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 161, 147]), - }, - sign_material: None, - }, - ), - ( - "cherry_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cherry_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 170, 164]), - }, - sign_material: None, - }, - ), - ( - "cherry_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("cherry"), - }, - ), - ( - "cherry_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([229, 172, 194]), - }, - sign_material: None, - }, - ), - ( - "cherry_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([185, 141, 137]), - }, - sign_material: None, - }, - ), - ( - "cherry_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cherry_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("cherry"), - }, - ), - ( - "cherry_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 178, 172]), - }, - sign_material: None, - }, - ), - ( - "cherry_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("cherry"), - }, - ), - ( - "cherry_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("cherry"), - }, - ), - ( - "cherry_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 33, 44]), - }, - sign_material: None, - }, - ), - ( - "chest", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "chipped_anvil", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 72]), - }, - sign_material: None, - }, - ), - ( - "chiseled_bookshelf", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([178, 144, 88]), - }, - sign_material: None, - }, - ), - ( - "chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([184, 100, 73]), - }, - sign_material: None, - }, - ), - ( - "chiseled_deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 54, 54]), - }, - sign_material: None, - }, - ), - ( - "chiseled_nether_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([45, 22, 27]), - }, - sign_material: None, - }, - ), - ( - "chiseled_polished_blackstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "chiseled_quartz_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([231, 226, 218]), - }, - sign_material: None, - }, - ), - ( - "chiseled_red_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "chiseled_resin_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([200, 84, 24]), - }, - sign_material: None, - }, - ), - ( - "chiseled_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "chiseled_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 118, 119]), - }, - sign_material: None, - }, - ), - ( - "chiseled_tuff", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([89, 94, 86]), - }, - sign_material: None, - }, - ), - ( - "chiseled_tuff_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 113, 106]), - }, - sign_material: None, - }, - ), - ( - "chorus_flower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([151, 120, 151]), - }, - sign_material: None, - }, - ), - ( - "chorus_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 57, 93]), - }, - sign_material: None, - }, - ), - ( - "clay", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 166, 179]), - }, - sign_material: None, - }, - ), - ( - "closed_eyeblossom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "coal_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([16, 15, 15]), - }, - sign_material: None, - }, - ), - ( - "coal_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([105, 105, 105]), - }, - sign_material: None, - }, - ), - ( - "coarse_dirt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 85, 59]), - }, - sign_material: None, - }, - ), - ( - "cobbled_deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 77, 80]), - }, - sign_material: None, - }, - ), - ( - "cobbled_deepslate_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 77, 80]), - }, - sign_material: None, - }, - ), - ( - "cobbled_deepslate_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 77, 80]), - }, - sign_material: None, - }, - ), - ( - "cobbled_deepslate_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 77, 80]), - }, - sign_material: None, - }, - ), - ( - "cobblestone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 127, 127]), - }, - sign_material: None, - }, - ), - ( - "cobblestone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 127, 127]), - }, - sign_material: None, - }, - ), - ( - "cobblestone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 127, 127]), - }, - sign_material: None, - }, - ), - ( - "cobblestone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 127, 127]), - }, - sign_material: None, - }, - ), - ( - "cobweb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([228, 233, 234]), - }, - sign_material: None, - }, - ), - ( - "cocoa", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 91, 40]), - }, - sign_material: None, - }, - ), - ( - "command_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 136, 108]), - }, - sign_material: None, - }, - ), - ( - "comparator", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([166, 161, 159]), - }, - sign_material: None, - }, - ), - ( - "composter", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([88, 61, 23]), - }, - sign_material: None, - }, - ), - ( - "conduit", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([159, 139, 113]), - }, - sign_material: None, - }, - ), - ( - "copper_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 107, 79]), - }, - sign_material: None, - }, - ), - ( - "copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([156, 86, 57]), - }, - sign_material: None, - }, - ), - ( - "copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 109, 82]), - }, - sign_material: None, - }, - ), - ( - "copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 107, 79]), - }, - sign_material: None, - }, - ), - ( - "copper_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 125, 120]), - }, - sign_material: None, - }, - ), - ( - "copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 106, 79]), - }, - sign_material: None, - }, - ), - ( - "cornflower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cracked_deepslate_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([64, 64, 65]), - }, - sign_material: None, - }, - ), - ( - "cracked_deepslate_tiles", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([52, 52, 52]), - }, - sign_material: None, - }, - ), - ( - "cracked_nether_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([40, 20, 23]), - }, - sign_material: None, - }, - ), - ( - "cracked_polished_blackstone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 37, 43]), - }, - sign_material: None, - }, - ), - ( - "cracked_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([118, 117, 118]), - }, - sign_material: None, - }, - ), - ( - "crafter", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 98, 99]), - }, - sign_material: None, - }, - ), - ( - "crafting_table", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 73, 42]), - }, - sign_material: None, - }, - ), - ( - "creaking_heart", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 59, 54]), - }, - sign_material: None, - }, - ), - ( - "creeper_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "creeper_wall_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "crimson_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "crimson_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 54, 79]), - }, - sign_material: None, - }, - ), - ( - "crimson_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_fungus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "crimson_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("crimson"), - }, - ), - ( - "crimson_hyphae", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([92, 25, 29]), - }, - sign_material: None, - }, - ), - ( - "crimson_nylium", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([130, 31, 31]), - }, - sign_material: None, - }, - ), - ( - "crimson_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([126, 8, 41]), - }, - sign_material: None, - }, - ), - ( - "crimson_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("crimson"), - }, - ), - ( - "crimson_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 48, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 49, 70]), - }, - sign_material: None, - }, - ), - ( - "crimson_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 50, 72]), - }, - sign_material: None, - }, - ), - ( - "crimson_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("crimson"), - }, - ), - ( - "crimson_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("crimson"), - }, - ), - ( - "crying_obsidian", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([32, 10, 60]), - }, - sign_material: None, - }, - ), - ( - "cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "cut_red_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "cut_red_sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "cut_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "cut_sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "cyan_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cyan_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cyan_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cyan_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "cyan_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([21, 137, 145]), - }, - sign_material: None, - }, - ), - ( - "cyan_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([21, 119, 136]), - }, - sign_material: None, - }, - ), - ( - "cyan_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([36, 147, 157]), - }, - sign_material: None, - }, - ), - ( - "cyan_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([52, 118, 125]), - }, - sign_material: None, - }, - ), - ( - "cyan_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 121, 135]), - }, - sign_material: None, - }, - ), - ( - "cyan_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([76, 127, 153]), - }, - sign_material: None, - }, - ), - ( - "cyan_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 122, 147]), - }, - sign_material: None, - }, - ), - ( - "cyan_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([86, 91, 91]), - }, - sign_material: None, - }, - ), - ( - "cyan_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "cyan_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([21, 137, 145]), - }, - sign_material: None, - }, - ), - ( - "damaged_anvil", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 72]), - }, - sign_material: None, - }, - ), - ( - "dandelion", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([76, 51, 25]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("dark_oak"), - }, - ), - ( - "dark_oak_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Foliage}), - color: Color([150, 150, 150]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([67, 45, 22]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([61, 90, 30]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("dark_oak"), - }, - ), - ( - "dark_oak_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 43, 20]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([75, 49, 23]), - }, - sign_material: None, - }, - ), - ( - "dark_oak_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("dark_oak"), - }, - ), - ( - "dark_oak_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("dark_oak"), - }, - ), - ( - "dark_oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([60, 46, 26]), - }, - sign_material: None, - }, - ), - ( - "dark_prismarine", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([51, 91, 75]), - }, - sign_material: None, - }, - ), - ( - "dark_prismarine_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([51, 91, 75]), - }, - sign_material: None, - }, - ), - ( - "dark_prismarine_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([51, 91, 75]), - }, - sign_material: None, - }, - ), - ( - "daylight_detector", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([130, 116, 94]), - }, - sign_material: None, - }, - ), - ( - "dead_brain_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_brain_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 117, 114]), - }, - sign_material: None, - }, - ), - ( - "dead_brain_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_brain_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_bubble_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_bubble_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 123, 119]), - }, - sign_material: None, - }, - ), - ( - "dead_bubble_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_bubble_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([107, 78, 40]), - }, - sign_material: None, - }, - ), - ( - "dead_fire_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_fire_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 123, 119]), - }, - sign_material: None, - }, - ), - ( - "dead_fire_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_fire_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_horn_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_horn_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([133, 126, 122]), - }, - sign_material: None, - }, - ), - ( - "dead_horn_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_horn_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_tube_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_tube_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([130, 123, 119]), - }, - sign_material: None, - }, - ), - ( - "dead_tube_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dead_tube_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "decorated_pot", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 68, 53]), - }, - sign_material: None, - }, - ), - ( - "deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 80, 82]), - }, - sign_material: None, - }, - ), - ( - "deepslate_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 70, 71]), - }, - sign_material: None, - }, - ), - ( - "deepslate_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 70, 71]), - }, - sign_material: None, - }, - ), - ( - "deepslate_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 70, 71]), - }, - sign_material: None, - }, - ), - ( - "deepslate_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 70, 71]), - }, - sign_material: None, - }, - ), - ( - "deepslate_coal_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([74, 74, 76]), - }, - sign_material: None, - }, - ), - ( - "deepslate_copper_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([92, 93, 89]), - }, - sign_material: None, - }, - ), - ( - "deepslate_diamond_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 106, 106]), - }, - sign_material: None, - }, - ), - ( - "deepslate_emerald_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([78, 104, 87]), - }, - sign_material: None, - }, - ), - ( - "deepslate_gold_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 102, 78]), - }, - sign_material: None, - }, - ), - ( - "deepslate_iron_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 99, 94]), - }, - sign_material: None, - }, - ), - ( - "deepslate_lapis_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 90, 115]), - }, - sign_material: None, - }, - ), - ( - "deepslate_redstone_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([104, 73, 74]), - }, - sign_material: None, - }, - ), - ( - "deepslate_tile_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 54, 55]), - }, - sign_material: None, - }, - ), - ( - "deepslate_tile_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 54, 55]), - }, - sign_material: None, - }, - ), - ( - "deepslate_tile_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 54, 55]), - }, - sign_material: None, - }, - ), - ( - "deepslate_tiles", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 54, 55]), - }, - sign_material: None, - }, - ), - ( - "detector_rail", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([123, 104, 90]), - }, - sign_material: None, - }, - ), - ( - "diamond_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 237, 228]), - }, - sign_material: None, - }, - ), - ( - "diamond_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([121, 141, 140]), - }, - sign_material: None, - }, - ), - ( - "diorite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([188, 188, 188]), - }, - sign_material: None, - }, - ), - ( - "diorite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([188, 188, 188]), - }, - sign_material: None, - }, - ), - ( - "diorite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([188, 188, 188]), - }, - sign_material: None, - }, - ), - ( - "diorite_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([188, 188, 188]), - }, - sign_material: None, - }, - ), - ( - "dirt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([134, 96, 67]), - }, - sign_material: None, - }, - ), - ( - "dirt_path", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([148, 121, 65]), - }, - sign_material: None, - }, - ), - ( - "dispenser", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 109, 109]), - }, - sign_material: None, - }, - ), - ( - "dragon_egg", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([12, 9, 15]), - }, - sign_material: None, - }, - ), - ( - "dragon_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dragon_wall_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "dried_ghast", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([179, 168, 168]), - }, - sign_material: None, - }, - ), - ( - "dried_kelp_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([50, 58, 38]), - }, - sign_material: None, - }, - ), - ( - "dripstone_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([134, 107, 92]), - }, - sign_material: None, - }, - ), - ( - "dropper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 109, 109]), - }, - sign_material: None, - }, - ), - ( - "emerald_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([42, 203, 87]), - }, - sign_material: None, - }, - ), - ( - "emerald_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 136, 115]), - }, - sign_material: None, - }, - ), - ( - "enchanting_table", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([128, 75, 85]), - }, - sign_material: None, - }, - ), - ( - "end_gateway", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([15, 10, 24]), - }, - sign_material: None, - }, - ), - ( - "end_portal", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([15, 10, 24]), - }, - sign_material: None, - }, - ), - ( - "end_portal_frame", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([91, 120, 97]), - }, - sign_material: None, - }, - ), - ( - "end_rod", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "end_stone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([219, 222, 158]), - }, - sign_material: None, - }, - ), - ( - "end_stone_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([218, 224, 162]), - }, - sign_material: None, - }, - ), - ( - "end_stone_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([218, 224, 162]), - }, - sign_material: None, - }, - ), - ( - "end_stone_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([218, 224, 162]), - }, - sign_material: None, - }, - ), - ( - "end_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([218, 224, 162]), - }, - sign_material: None, - }, - ), - ( - "ender_chest", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([15, 10, 24]), - }, - sign_material: None, - }, - ), - ( - "exposed_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 119, 100]), - }, - sign_material: None, - }, - ), - ( - "exposed_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 103]), - }, - sign_material: None, - }, - ), - ( - "exposed_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([135, 107, 89]), - }, - sign_material: None, - }, - ), - ( - "exposed_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([164, 123, 106]), - }, - sign_material: None, - }, - ), - ( - "exposed_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 104]), - }, - sign_material: None, - }, - ), - ( - "exposed_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 104]), - }, - sign_material: None, - }, - ), - ( - "exposed_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "exposed_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "exposed_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "farmland", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([81, 44, 15]), - }, - sign_material: None, - }, - ), - ( - "fern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "fire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([211, 140, 53]), - }, - sign_material: None, - }, - ), - ( - "fire_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "fire_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([163, 35, 46]), - }, - sign_material: None, - }, - ), - ( - "fire_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "fire_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "firefly_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([87, 83, 43]), - }, - sign_material: None, - }, - ), - ( - "fletching_table", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([197, 180, 133]), - }, - sign_material: None, - }, - ), - ( - "flower_pot", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 68, 53]), - }, - sign_material: None, - }, - ), - ( - "flowering_azalea", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 121, 64]), - }, - sign_material: None, - }, - ), - ( - "flowering_azalea_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 111, 60]), - }, - sign_material: None, - }, - ), - ( - "frogspawn", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([105, 90, 82]), - }, - sign_material: None, - }, - ), - ( - "frosted_ice", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([140, 181, 252]), - }, - sign_material: None, - }, - ), - ( - "furnace", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 109, 109]), - }, - sign_material: None, - }, - ), - ( - "gilded_blackstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([55, 42, 38]), - }, - sign_material: None, - }, - ), - ( - "glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([175, 213, 219]), - }, - sign_material: None, - }, - ), - ( - "glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([170, 210, 217]), - }, - sign_material: None, - }, - ), - ( - "glow_item_frame", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "glow_lichen", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "glowstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([171, 131, 84]), - }, - sign_material: None, - }, - ), - ( - "gold_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([246, 208, 61]), - }, - sign_material: None, - }, - ), - ( - "gold_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([145, 133, 106]), - }, - sign_material: None, - }, - ), - ( - "granite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 103, 85]), - }, - sign_material: None, - }, - ), - ( - "granite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 103, 85]), - }, - sign_material: None, - }, - ), - ( - "granite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 103, 85]), - }, - sign_material: None, - }, - ), - ( - "granite_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 103, 85]), - }, - sign_material: None, - }, - ), - ( - "grass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "grass_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([147, 147, 147]), - }, - sign_material: None, - }, - ), - ( - "grass_path", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([148, 121, 65]), - }, - sign_material: None, - }, - ), - ( - "gravel", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 127, 126]), - }, - sign_material: None, - }, - ), - ( - "gray_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "gray_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "gray_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "gray_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "gray_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([62, 68, 71]), - }, - sign_material: None, - }, - ), - ( - "gray_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 57, 61]), - }, - sign_material: None, - }, - ), - ( - "gray_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([76, 81, 84]), - }, - sign_material: None, - }, - ), - ( - "gray_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 90, 93]), - }, - sign_material: None, - }, - ), - ( - "gray_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([55, 58, 62]), - }, - sign_material: None, - }, - ), - ( - "gray_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([76, 76, 76]), - }, - sign_material: None, - }, - ), - ( - "gray_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 73, 73]), - }, - sign_material: None, - }, - ), - ( - "gray_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([57, 42, 35]), - }, - sign_material: None, - }, - ), - ( - "gray_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "gray_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([62, 68, 71]), - }, - sign_material: None, - }, - ), - ( - "green_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "green_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "green_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "green_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "green_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([84, 109, 27]), - }, - sign_material: None, - }, - ), - ( - "green_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 91, 36]), - }, - sign_material: None, - }, - ), - ( - "green_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 119, 44]), - }, - sign_material: None, - }, - ), - ( - "green_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 142, 67]), - }, - sign_material: None, - }, - ), - ( - "green_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 100, 31]), - }, - sign_material: None, - }, - ), - ( - "green_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([102, 127, 51]), - }, - sign_material: None, - }, - ), - ( - "green_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 122, 48]), - }, - sign_material: None, - }, - ), - ( - "green_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([76, 83, 42]), - }, - sign_material: None, - }, - ), - ( - "green_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "green_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([84, 109, 27]), - }, - sign_material: None, - }, - ), - ( - "grindstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 142, 142]), - }, - sign_material: None, - }, - ), - ( - "hanging_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 115, 91]), - }, - sign_material: None, - }, - ), - ( - "hay_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([165, 139, 12]), - }, - sign_material: None, - }, - ), - ( - "heavy_core", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 86, 94]), - }, - sign_material: None, - }, - ), - ( - "heavy_weighted_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([220, 220, 220]), - }, - sign_material: None, - }, - ), - ( - "honey_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([251, 185, 52]), - }, - sign_material: None, - }, - ), - ( - "honeycomb_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([229, 148, 29]), - }, - sign_material: None, - }, - ), - ( - "hopper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([75, 74, 75]), - }, - sign_material: None, - }, - ), - ( - "horn_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "horn_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([216, 199, 66]), - }, - sign_material: None, - }, - ), - ( - "horn_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "horn_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "ice", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([145, 183, 253]), - }, - sign_material: None, - }, - ), - ( - "infested_chiseled_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 118, 119]), - }, - sign_material: None, - }, - ), - ( - "infested_cobblestone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 127, 127]), - }, - sign_material: None, - }, - ), - ( - "infested_cracked_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([118, 117, 118]), - }, - sign_material: None, - }, - ), - ( - "infested_deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 80, 82]), - }, - sign_material: None, - }, - ), - ( - "infested_mossy_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 121, 105]), - }, - sign_material: None, - }, - ), - ( - "infested_stone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "infested_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 121, 122]), - }, - sign_material: None, - }, - ), - ( - "iron_bars", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 139, 135]), - }, - sign_material: None, - }, - ), - ( - "iron_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([220, 220, 220]), - }, - sign_material: None, - }, - ), - ( - "iron_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([194, 193, 193]), - }, - sign_material: None, - }, - ), - ( - "iron_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([136, 129, 122]), - }, - sign_material: None, - }, - ), - ( - "iron_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([202, 202, 202]), - }, - sign_material: None, - }, - ), - ( - "item_frame", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "jack_o_lantern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([214, 152, 52]), - }, - sign_material: None, - }, - ), - ( - "jigsaw", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 69, 81]), - }, - sign_material: None, - }, - ), - ( - "jukebox", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 64, 47]), - }, - sign_material: None, - }, - ), - ( - "jungle_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "jungle_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([163, 119, 84]), - }, - sign_material: None, - }, - ), - ( - "jungle_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("jungle"), - }, - ), - ( - "jungle_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Foliage}), - color: Color([156, 154, 143]), - }, - sign_material: None, - }, - ), - ( - "jungle_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 109, 70]), - }, - sign_material: None, - }, - ), - ( - "jungle_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([47, 81, 16]), - }, - sign_material: None, - }, - ), - ( - "jungle_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("jungle"), - }, - ), - ( - "jungle_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 115, 80]), - }, - sign_material: None, - }, - ), - ( - "jungle_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([152, 110, 77]), - }, - sign_material: None, - }, - ), - ( - "jungle_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("jungle"), - }, - ), - ( - "jungle_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("jungle"), - }, - ), - ( - "jungle_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([85, 67, 25]), - }, - sign_material: None, - }, - ), - ( - "kelp", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "kelp_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([86, 130, 42]), - }, - sign_material: None, - }, - ), - ( - "ladder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lantern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 91, 83]), - }, - sign_material: None, - }, - ), - ( - "lapis_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([30, 67, 140]), - }, - sign_material: None, - }, - ), - ( - "lapis_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([107, 117, 141]), - }, - sign_material: None, - }, - ), - ( - "large_amethyst_bud", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "large_fern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "lava", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([212, 90, 18]), - }, - sign_material: None, - }, - ), - ( - "lava_cauldron", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 72, 74]), - }, - sign_material: None, - }, - ), - ( - "leaf_litter", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lectern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([173, 137, 83]), - }, - sign_material: None, - }, - ), - ( - "lever", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_blue_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_blue_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_blue_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_blue_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "light_blue_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([58, 175, 217]), - }, - sign_material: None, - }, - ), - ( - "light_blue_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([35, 137, 198]), - }, - sign_material: None, - }, - ), - ( - "light_blue_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([74, 180, 213]), - }, - sign_material: None, - }, - ), - ( - "light_blue_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([94, 164, 208]), - }, - sign_material: None, - }, - ), - ( - "light_blue_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([49, 163, 212]), - }, - sign_material: None, - }, - ), - ( - "light_blue_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([102, 153, 216]), - }, - sign_material: None, - }, - ), - ( - "light_blue_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 147, 208]), - }, - sign_material: None, - }, - ), - ( - "light_blue_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([113, 108, 137]), - }, - sign_material: None, - }, - ), - ( - "light_blue_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_blue_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([58, 175, 217]), - }, - sign_material: None, - }, - ), - ( - "light_gray_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_gray_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_gray_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_gray_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "light_gray_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 142, 134]), - }, - sign_material: None, - }, - ), - ( - "light_gray_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 115]), - }, - sign_material: None, - }, - ), - ( - "light_gray_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 154, 148]), - }, - sign_material: None, - }, - ), - ( - "light_gray_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([144, 166, 167]), - }, - sign_material: None, - }, - ), - ( - "light_gray_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 124, 115]), - }, - sign_material: None, - }, - ), - ( - "light_gray_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([153, 153, 153]), - }, - sign_material: None, - }, - ), - ( - "light_gray_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([147, 147, 147]), - }, - sign_material: None, - }, - ), - ( - "light_gray_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([135, 106, 97]), - }, - sign_material: None, - }, - ), - ( - "light_gray_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "light_gray_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 142, 134]), - }, - sign_material: None, - }, - ), - ( - "light_weighted_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([246, 208, 61]), - }, - sign_material: None, - }, - ), - ( - "lightning_rod", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lilac", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 125, 147]), - }, - sign_material: None, - }, - ), - ( - "lily_of_the_valley", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lily_pad", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([133, 133, 133]), - }, - sign_material: None, - }, - ), - ( - "lime_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lime_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lime_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lime_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "lime_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 185, 25]), - }, - sign_material: None, - }, - ), - ( - "lime_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([94, 168, 24]), - }, - sign_material: None, - }, - ), - ( - "lime_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 189, 41]), - }, - sign_material: None, - }, - ), - ( - "lime_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 197, 55]), - }, - sign_material: None, - }, - ), - ( - "lime_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 172, 23]), - }, - sign_material: None, - }, - ), - ( - "lime_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 204, 25]), - }, - sign_material: None, - }, - ), - ( - "lime_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 196, 24]), - }, - sign_material: None, - }, - ), - ( - "lime_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 117, 52]), - }, - sign_material: None, - }, - ), - ( - "lime_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "lime_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 185, 25]), - }, - sign_material: None, - }, - ), - ( - "lodestone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([147, 149, 152]), - }, - sign_material: None, - }, - ), - ( - "loom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 119, 91]), - }, - sign_material: None, - }, - ), - ( - "magenta_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "magenta_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "magenta_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "magenta_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "magenta_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([189, 68, 179]), - }, - sign_material: None, - }, - ), - ( - "magenta_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([169, 48, 159]), - }, - sign_material: None, - }, - ), - ( - "magenta_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 83, 184]), - }, - sign_material: None, - }, - ), - ( - "magenta_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([208, 100, 191]), - }, - sign_material: None, - }, - ), - ( - "magenta_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([173, 54, 163]), - }, - sign_material: None, - }, - ), - ( - "magenta_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([178, 76, 216]), - }, - sign_material: None, - }, - ), - ( - "magenta_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([171, 73, 208]), - }, - sign_material: None, - }, - ), - ( - "magenta_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([149, 88, 108]), - }, - sign_material: None, - }, - ), - ( - "magenta_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "magenta_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([189, 68, 179]), - }, - sign_material: None, - }, - ), - ( - "magma_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 63, 31]), - }, - sign_material: None, - }, - ), - ( - "mangrove_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "mangrove_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 48, 46]), - }, - sign_material: None, - }, - ), - ( - "mangrove_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("mangrove"), - }, - ), - ( - "mangrove_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Foliage}), - color: Color([129, 128, 128]), - }, - sign_material: None, - }, - ), - ( - "mangrove_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([102, 48, 42]), - }, - sign_material: None, - }, - ), - ( - "mangrove_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_propagule", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([96, 174, 83]), - }, - sign_material: None, - }, - ), - ( - "mangrove_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([74, 59, 38]), - }, - sign_material: None, - }, - ), - ( - "mangrove_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("mangrove"), - }, - ), - ( - "mangrove_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 54, 48]), - }, - sign_material: None, - }, - ), - ( - "mangrove_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 46, 42]), - }, - sign_material: None, - }, - ), - ( - "mangrove_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("mangrove"), - }, - ), - ( - "mangrove_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("mangrove"), - }, - ), - ( - "mangrove_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 66, 41]), - }, - sign_material: None, - }, - ), - ( - "medium_amethyst_bud", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "melon", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([111, 144, 30]), - }, - sign_material: None, - }, - ), - ( - "melon_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([153, 153, 153]), - }, - sign_material: None, - }, - ), - ( - "moss_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([89, 109, 45]), - }, - sign_material: None, - }, - ), - ( - "moss_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([89, 109, 45]), - }, - sign_material: None, - }, - ), - ( - "mossy_cobblestone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 118, 94]), - }, - sign_material: None, - }, - ), - ( - "mossy_cobblestone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 118, 94]), - }, - sign_material: None, - }, - ), - ( - "mossy_cobblestone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 118, 94]), - }, - sign_material: None, - }, - ), - ( - "mossy_cobblestone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 118, 94]), - }, - sign_material: None, - }, - ), - ( - "mossy_stone_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 121, 105]), - }, - sign_material: None, - }, - ), - ( - "mossy_stone_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 121, 105]), - }, - sign_material: None, - }, - ), - ( - "mossy_stone_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 121, 105]), - }, - sign_material: None, - }, - ), - ( - "mossy_stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 121, 105]), - }, - sign_material: None, - }, - ), - ( - "moving_piston", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "mud", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([60, 57, 60]), - }, - sign_material: None, - }, - ), - ( - "mud_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 103, 79]), - }, - sign_material: None, - }, - ), - ( - "mud_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 103, 79]), - }, - sign_material: None, - }, - ), - ( - "mud_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 103, 79]), - }, - sign_material: None, - }, - ), - ( - "mud_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 103, 79]), - }, - sign_material: None, - }, - ), - ( - "muddy_mangrove_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 58, 45]), - }, - sign_material: None, - }, - ), - ( - "mushroom_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([203, 196, 185]), - }, - sign_material: None, - }, - ), - ( - "mycelium", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([111, 98, 101]), - }, - sign_material: None, - }, - ), - ( - "nether_brick_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 21, 26]), - }, - sign_material: None, - }, - ), - ( - "nether_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 21, 26]), - }, - sign_material: None, - }, - ), - ( - "nether_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 21, 26]), - }, - sign_material: None, - }, - ), - ( - "nether_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 21, 26]), - }, - sign_material: None, - }, - ), - ( - "nether_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 21, 26]), - }, - sign_material: None, - }, - ), - ( - "nether_gold_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 54, 42]), - }, - sign_material: None, - }, - ), - ( - "nether_portal", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([89, 11, 192]), - }, - sign_material: None, - }, - ), - ( - "nether_quartz_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([117, 65, 62]), - }, - sign_material: None, - }, - ), - ( - "nether_sprouts", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([19, 151, 133]), - }, - sign_material: None, - }, - ), - ( - "nether_wart", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([111, 18, 19]), - }, - sign_material: None, - }, - ), - ( - "nether_wart_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 2, 2]), - }, - sign_material: None, - }, - ), - ( - "netherite_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([66, 61, 63]), - }, - sign_material: None, - }, - ), - ( - "netherrack", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 38, 38]), - }, - sign_material: None, - }, - ), - ( - "note_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([88, 58, 40]), - }, - sign_material: None, - }, - ), - ( - "oak_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "oak_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([140, 110, 66]), - }, - sign_material: None, - }, - ), - ( - "oak_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "oak_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Foliage}), - color: Color([144, 144, 144]), - }, - sign_material: None, - }, - ), - ( - "oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([151, 121, 73]), - }, - sign_material: None, - }, - ), - ( - "oak_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 106, 40]), - }, - sign_material: None, - }, - ), - ( - "oak_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "oak_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "oak_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([124, 99, 56]), - }, - sign_material: None, - }, - ), - ( - "oak_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "oak_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 85, 50]), - }, - sign_material: None, - }, - ), - ( - "observer", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 98, 98]), - }, - sign_material: None, - }, - ), - ( - "obsidian", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([15, 10, 24]), - }, - sign_material: None, - }, - ), - ( - "ochre_froglight", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([250, 245, 206]), - }, - sign_material: None, - }, - ), - ( - "open_eyeblossom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "orange_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([240, 118, 19]), - }, - sign_material: None, - }, - ), - ( - "orange_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([224, 97, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 131, 31]), - }, - sign_material: None, - }, - ), - ( - "orange_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 147, 91]), - }, - sign_material: None, - }, - ), - ( - "orange_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([234, 106, 8]), - }, - sign_material: None, - }, - ), - ( - "orange_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([216, 127, 51]), - }, - sign_material: None, - }, - ), - ( - "orange_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([208, 122, 48]), - }, - sign_material: None, - }, - ), - ( - "orange_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 83, 37]), - }, - sign_material: None, - }, - ), - ( - "orange_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "orange_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([240, 118, 19]), - }, - sign_material: None, - }, - ), - ( - "oxeye_daisy", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "oxidized_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 161, 132]), - }, - sign_material: None, - }, - ), - ( - "oxidized_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 162, 132]), - }, - sign_material: None, - }, - ), - ( - "oxidized_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 132, 109]), - }, - sign_material: None, - }, - ), - ( - "oxidized_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 160, 132]), - }, - sign_material: None, - }, - ), - ( - "oxidized_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 161, 131]), - }, - sign_material: None, - }, - ), - ( - "oxidized_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 161, 132]), - }, - sign_material: None, - }, - ), - ( - "oxidized_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "oxidized_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "oxidized_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "packed_ice", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([141, 180, 250]), - }, - sign_material: None, - }, - ), - ( - "packed_mud", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 106, 79]), - }, - sign_material: None, - }, - ), - ( - "pale_hanging_moss", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pale_moss_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 112, 104]), - }, - sign_material: None, - }, - ), - ( - "pale_moss_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 112, 104]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([216, 208, 206]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("pale_oak"), - }, - ), - ( - "pale_oak_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([116, 121, 114]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([198, 189, 187]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 105, 99]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("pale_oak"), - }, - ), - ( - "pale_oak_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([227, 217, 216]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([229, 220, 218]), - }, - sign_material: None, - }, - ), - ( - "pale_oak_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("pale_oak"), - }, - ), - ( - "pale_oak_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("pale_oak"), - }, - ), - ( - "pale_oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([87, 77, 75]), - }, - sign_material: None, - }, - ), - ( - "pearlescent_froglight", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([245, 240, 239]), - }, - sign_material: None, - }, - ), - ( - "peony", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([129, 126, 139]), - }, - sign_material: None, - }, - ), - ( - "petrified_oak_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "piglin_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "piglin_wall_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "pink_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([237, 141, 172]), - }, - sign_material: None, - }, - ), - ( - "pink_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([213, 101, 142]), - }, - sign_material: None, - }, - ), - ( - "pink_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([228, 153, 181]), - }, - sign_material: None, - }, - ), - ( - "pink_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 154, 181]), - }, - sign_material: None, - }, - ), - ( - "pink_petals", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([230, 121, 157]), - }, - sign_material: None, - }, - ), - ( - "pink_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([242, 127, 165]), - }, - sign_material: None, - }, - ), - ( - "pink_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([233, 122, 159]), - }, - sign_material: None, - }, - ), - ( - "pink_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 78, 78]), - }, - sign_material: None, - }, - ), - ( - "pink_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "pink_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([237, 141, 172]), - }, - sign_material: None, - }, - ), - ( - "piston", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 104, 96]), - }, - sign_material: None, - }, - ), - ( - "piston_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([153, 127, 85]), - }, - sign_material: None, - }, - ), - ( - "pitcher_crop", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([193, 165, 103]), - }, - sign_material: None, - }, - ), - ( - "pitcher_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 144, 189]), - }, - sign_material: None, - }, - ), - ( - "player_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "player_wall_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "podzol", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([91, 63, 24]), - }, - sign_material: None, - }, - ), - ( - "pointed_dripstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([129, 102, 89]), - }, - sign_material: None, - }, - ), - ( - "polished_andesite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([132, 134, 133]), - }, - sign_material: None, - }, - ), - ( - "polished_andesite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([132, 134, 133]), - }, - sign_material: None, - }, - ), - ( - "polished_andesite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([132, 134, 133]), - }, - sign_material: None, - }, - ), - ( - "polished_basalt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 98, 100]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([48, 42, 49]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([48, 42, 49]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([48, 42, 49]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([48, 42, 49]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "polished_blackstone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 48, 56]), - }, - sign_material: None, - }, - ), - ( - "polished_deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 73]), - }, - sign_material: None, - }, - ), - ( - "polished_deepslate_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 73]), - }, - sign_material: None, - }, - ), - ( - "polished_deepslate_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 73]), - }, - sign_material: None, - }, - ), - ( - "polished_deepslate_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 73]), - }, - sign_material: None, - }, - ), - ( - "polished_diorite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 193, 194]), - }, - sign_material: None, - }, - ), - ( - "polished_diorite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 193, 194]), - }, - sign_material: None, - }, - ), - ( - "polished_diorite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 193, 194]), - }, - sign_material: None, - }, - ), - ( - "polished_granite", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 106, 89]), - }, - sign_material: None, - }, - ), - ( - "polished_granite_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 106, 89]), - }, - sign_material: None, - }, - ), - ( - "polished_granite_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 106, 89]), - }, - sign_material: None, - }, - ), - ( - "polished_tuff", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "polished_tuff_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "polished_tuff_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "polished_tuff_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([97, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "poppy", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "potatoes", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([84, 135, 47]), - }, - sign_material: None, - }, - ), - ( - "potted_acacia_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([118, 117, 23]), - }, - sign_material: None, - }, - ), - ( - "potted_allium", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([158, 137, 183]), - }, - sign_material: None, - }, - ), - ( - "potted_azalea_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([101, 124, 47]), - }, - sign_material: None, - }, - ), - ( - "potted_azure_bluet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([169, 204, 127]), - }, - sign_material: None, - }, - ), - ( - "potted_bamboo", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 144, 19]), - }, - sign_material: None, - }, - ), - ( - "potted_birch_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 160, 79]), - }, - sign_material: None, - }, - ), - ( - "potted_blue_orchid", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([47, 162, 168]), - }, - sign_material: None, - }, - ), - ( - "potted_brown_mushroom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([153, 116, 92]), - }, - sign_material: None, - }, - ), - ( - "potted_cactus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([85, 127, 43]), - }, - sign_material: None, - }, - ), - ( - "potted_cherry_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([164, 117, 143]), - }, - sign_material: None, - }, - ), - ( - "potted_closed_eyeblossom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 98, 101]), - }, - sign_material: None, - }, - ), - ( - "potted_cornflower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 121, 146]), - }, - sign_material: None, - }, - ), - ( - "potted_crimson_fungus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([141, 44, 29]), - }, - sign_material: None, - }, - ), - ( - "potted_crimson_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 8, 41]), - }, - sign_material: None, - }, - ), - ( - "potted_dandelion", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([147, 172, 43]), - }, - sign_material: None, - }, - ), - ( - "potted_dark_oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([61, 90, 30]), - }, - sign_material: None, - }, - ), - ( - "potted_dead_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([107, 78, 40]), - }, - sign_material: None, - }, - ), - ( - "potted_fern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([124, 124, 124]), - }, - sign_material: None, - }, - ), - ( - "potted_flowering_azalea_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([112, 121, 64]), - }, - sign_material: None, - }, - ), - ( - "potted_jungle_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([47, 81, 16]), - }, - sign_material: None, - }, - ), - ( - "potted_lily_of_the_valley", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([123, 174, 95]), - }, - sign_material: None, - }, - ), - ( - "potted_mangrove_propagule", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([96, 174, 83]), - }, - sign_material: None, - }, - ), - ( - "potted_oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([77, 106, 40]), - }, - sign_material: None, - }, - ), - ( - "potted_open_eyeblossom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([133, 124, 127]), - }, - sign_material: None, - }, - ), - ( - "potted_orange_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 142, 30]), - }, - sign_material: None, - }, - ), - ( - "potted_oxeye_daisy", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([179, 202, 143]), - }, - sign_material: None, - }, - ), - ( - "potted_pale_oak_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 105, 99]), - }, - sign_material: None, - }, - ), - ( - "potted_pink_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 157, 78]), - }, - sign_material: None, - }, - ), - ( - "potted_poppy", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([128, 64, 37]), - }, - sign_material: None, - }, - ), - ( - "potted_red_mushroom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([216, 75, 67]), - }, - sign_material: None, - }, - ), - ( - "potted_red_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([89, 128, 32]), - }, - sign_material: None, - }, - ), - ( - "potted_spruce_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 60, 36]), - }, - sign_material: None, - }, - ), - ( - "potted_torchflower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([100, 101, 77]), - }, - sign_material: None, - }, - ), - ( - "potted_warped_fungus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([74, 109, 87]), - }, - sign_material: None, - }, - ), - ( - "potted_warped_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 136, 123]), - }, - sign_material: None, - }, - ), - ( - "potted_white_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([93, 164, 71]), - }, - sign_material: None, - }, - ), - ( - "potted_wither_rose", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([41, 44, 23]), - }, - sign_material: None, - }, - ), - ( - "powder_snow", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 253, 253]), - }, - sign_material: None, - }, - ), - ( - "powder_snow_cauldron", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 72, 74]), - }, - sign_material: None, - }, - ), - ( - "powered_rail", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 109, 74]), - }, - sign_material: None, - }, - ), - ( - "prismarine", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 156, 151]), - }, - sign_material: None, - }, - ), - ( - "prismarine_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 171, 158]), - }, - sign_material: None, - }, - ), - ( - "prismarine_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 171, 158]), - }, - sign_material: None, - }, - ), - ( - "prismarine_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 171, 158]), - }, - sign_material: None, - }, - ), - ( - "prismarine_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 156, 151]), - }, - sign_material: None, - }, - ), - ( - "prismarine_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 156, 151]), - }, - sign_material: None, - }, - ), - ( - "prismarine_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([99, 156, 151]), - }, - sign_material: None, - }, - ), - ( - "pumpkin", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([198, 118, 24]), - }, - sign_material: None, - }, - ), - ( - "pumpkin_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([154, 154, 154]), - }, - sign_material: None, - }, - ), - ( - "purple_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "purple_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "purple_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "purple_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "purple_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([121, 42, 172]), - }, - sign_material: None, - }, - ), - ( - "purple_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([100, 31, 156]), - }, - sign_material: None, - }, - ), - ( - "purple_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 55, 177]), - }, - sign_material: None, - }, - ), - ( - "purple_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 47, 152]), - }, - sign_material: None, - }, - ), - ( - "purple_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 32, 156]), - }, - sign_material: None, - }, - ), - ( - "purple_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([127, 63, 178]), - }, - sign_material: None, - }, - ), - ( - "purple_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 61, 171]), - }, - sign_material: None, - }, - ), - ( - "purple_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([118, 70, 86]), - }, - sign_material: None, - }, - ), - ( - "purple_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "purple_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([121, 42, 172]), - }, - sign_material: None, - }, - ), - ( - "purpur_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([169, 125, 169]), - }, - sign_material: None, - }, - ), - ( - "purpur_pillar", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([171, 129, 171]), - }, - sign_material: None, - }, - ), - ( - "purpur_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([169, 125, 169]), - }, - sign_material: None, - }, - ), - ( - "purpur_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([169, 125, 169]), - }, - sign_material: None, - }, - ), - ( - "quartz_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "quartz_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([234, 229, 221]), - }, - sign_material: None, - }, - ), - ( - "quartz_pillar", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 230, 224]), - }, - sign_material: None, - }, - ), - ( - "quartz_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "quartz_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "rail", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 111, 88]), - }, - sign_material: None, - }, - ), - ( - "raw_copper_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 105, 79]), - }, - sign_material: None, - }, - ), - ( - "raw_gold_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([221, 169, 46]), - }, - sign_material: None, - }, - ), - ( - "raw_iron_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([166, 135, 107]), - }, - sign_material: None, - }, - ), - ( - "red_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "red_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 39, 34]), - }, - sign_material: None, - }, - ), - ( - "red_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 32, 32]), - }, - sign_material: None, - }, - ), - ( - "red_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([168, 54, 50]), - }, - sign_material: None, - }, - ), - ( - "red_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 59, 53]), - }, - sign_material: None, - }, - ), - ( - "red_mushroom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_mushroom_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([200, 46, 45]), - }, - sign_material: None, - }, - ), - ( - "red_nether_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([69, 7, 9]), - }, - sign_material: None, - }, - ), - ( - "red_nether_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([69, 7, 9]), - }, - sign_material: None, - }, - ), - ( - "red_nether_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([69, 7, 9]), - }, - sign_material: None, - }, - ), - ( - "red_nether_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([69, 7, 9]), - }, - sign_material: None, - }, - ), - ( - "red_sand", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 102, 33]), - }, - sign_material: None, - }, - ), - ( - "red_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "red_sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "red_sandstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "red_sandstone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "red_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([140, 31, 30]), - }, - sign_material: None, - }, - ), - ( - "red_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([153, 51, 51]), - }, - sign_material: None, - }, - ), - ( - "red_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([147, 48, 48]), - }, - sign_material: None, - }, - ), - ( - "red_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([143, 61, 46]), - }, - sign_material: None, - }, - ), - ( - "red_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "red_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 39, 34]), - }, - sign_material: None, - }, - ), - ( - "redstone_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([175, 24, 5]), - }, - sign_material: None, - }, - ), - ( - "redstone_lamp", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([95, 54, 30]), - }, - sign_material: None, - }, - ), - ( - "redstone_ore", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([140, 109, 109]), - }, - sign_material: None, - }, - ), - ( - "redstone_torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "redstone_wall_torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "redstone_wire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([175, 24, 5]), - }, - sign_material: None, - }, - ), - ( - "reinforced_deepslate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 82, 78]), - }, - sign_material: None, - }, - ), - ( - "repeater", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 157, 156]), - }, - sign_material: None, - }, - ), - ( - "repeating_command_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([129, 111, 176]), - }, - sign_material: None, - }, - ), - ( - "resin_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([217, 99, 25]), - }, - sign_material: None, - }, - ), - ( - "resin_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([205, 88, 24]), - }, - sign_material: None, - }, - ), - ( - "resin_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([205, 88, 24]), - }, - sign_material: None, - }, - ), - ( - "resin_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([205, 88, 24]), - }, - sign_material: None, - }, - ), - ( - "resin_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([205, 88, 24]), - }, - sign_material: None, - }, - ), - ( - "resin_clump", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "respawn_anchor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([75, 26, 144]), - }, - sign_material: None, - }, - ), - ( - "rooted_dirt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([144, 103, 76]), - }, - sign_material: None, - }, - ), - ( - "rose_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([131, 66, 37]), - }, - sign_material: None, - }, - ), - ( - "sand", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([219, 207, 163]), - }, - sign_material: None, - }, - ), - ( - "sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "sandstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "sandstone_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "scaffolding", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([170, 131, 73]), - }, - sign_material: None, - }, - ), - ( - "sculk", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([12, 29, 36]), - }, - sign_material: None, - }, - ), - ( - "sculk_catalyst", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([15, 31, 38]), - }, - sign_material: None, - }, - ), - ( - "sculk_sensor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([7, 70, 84]), - }, - sign_material: None, - }, - ), - ( - "sculk_shrieker", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([198, 205, 169]), - }, - sign_material: None, - }, - ), - ( - "sculk_vein", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([7, 48, 57]), - }, - sign_material: None, - }, - ), - ( - "sea_lantern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([172, 199, 190]), - }, - sign_material: None, - }, - ), - ( - "sea_pickle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([90, 97, 39]), - }, - sign_material: None, - }, - ), - ( - "seagrass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([50, 126, 8]), - }, - sign_material: None, - }, - ), - ( - "short_dry_grass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([187, 158, 108]), - }, - sign_material: None, - }, - ), - ( - "short_grass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "shroomlight", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([240, 146, 70]), - }, - sign_material: None, - }, - ), - ( - "shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([139, 96, 139]), - }, - sign_material: None, - }, - ), - ( - "sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "skeleton_skull", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "skeleton_wall_skull", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "slime_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([111, 192, 91]), - }, - sign_material: None, - }, - ), - ( - "small_amethyst_bud", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "small_dripleaf", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "smithing_table", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([57, 58, 70]), - }, - sign_material: None, - }, - ), - ( - "smoker", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([85, 83, 81]), - }, - sign_material: None, - }, - ), - ( - "smooth_basalt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 72, 78]), - }, - sign_material: None, - }, - ), - ( - "smooth_quartz", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "smooth_quartz_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "smooth_quartz_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 229, 222]), - }, - sign_material: None, - }, - ), - ( - "smooth_red_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "smooth_red_sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "smooth_red_sandstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([181, 97, 31]), - }, - sign_material: None, - }, - ), - ( - "smooth_sandstone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "smooth_sandstone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "smooth_sandstone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([223, 214, 170]), - }, - sign_material: None, - }, - ), - ( - "smooth_stone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([158, 158, 158]), - }, - sign_material: None, - }, - ), - ( - "smooth_stone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([158, 158, 158]), - }, - sign_material: None, - }, - ), - ( - "sniffer_egg", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([135, 105, 67]), - }, - sign_material: None, - }, - ), - ( - "snow", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([249, 254, 254]), - }, - sign_material: None, - }, - ), - ( - "snow_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([249, 254, 254]), - }, - sign_material: None, - }, - ), - ( - "soul_campfire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([80, 204, 208]), - }, - sign_material: None, - }, - ), - ( - "soul_fire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([51, 192, 197]), - }, - sign_material: None, - }, - ), - ( - "soul_lantern", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([71, 99, 114]), - }, - sign_material: None, - }, - ), - ( - "soul_sand", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([81, 62, 50]), - }, - sign_material: None, - }, - ), - ( - "soul_soil", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([75, 57, 46]), - }, - sign_material: None, - }, - ), - ( - "soul_torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "soul_wall_torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "spawner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([36, 46, 62]), - }, - sign_material: None, - }, - ), - ( - "sponge", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([195, 192, 74]), - }, - sign_material: None, - }, - ), - ( - "spore_blossom", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([206, 96, 158]), - }, - sign_material: None, - }, - ), - ( - "spruce_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "spruce_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 80, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("spruce"), - }, - ), - ( - "spruce_leaves", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Spruce}), - color: Color([126, 126, 126]), - }, - sign_material: None, - }, - ), - ( - "spruce_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 80, 46]), - }, - sign_material: None, - }, - ), - ( - "spruce_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_sapling", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 60, 36]), - }, - sign_material: None, - }, - ), - ( - "spruce_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("spruce"), - }, - ), - ( - "spruce_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([114, 84, 48]), - }, - sign_material: None, - }, - ), - ( - "spruce_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([103, 79, 47]), - }, - sign_material: None, - }, - ), - ( - "spruce_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("spruce"), - }, - ), - ( - "spruce_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("spruce"), - }, - ), - ( - "spruce_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([58, 37, 16]), - }, - sign_material: None, - }, - ), - ( - "sticky_piston", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 104, 96]), - }, - sign_material: None, - }, - ), - ( - "stone", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "stone_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 121, 122]), - }, - sign_material: None, - }, - ), - ( - "stone_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 121, 122]), - }, - sign_material: None, - }, - ), - ( - "stone_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 121, 122]), - }, - sign_material: None, - }, - ), - ( - "stone_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([122, 121, 122]), - }, - sign_material: None, - }, - ), - ( - "stone_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "stone_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "stone_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "stone_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([125, 125, 125]), - }, - sign_material: None, - }, - ), - ( - "stonecutter", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([123, 118, 111]), - }, - sign_material: None, - }, - ), - ( - "stripped_acacia_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([166, 91, 51]), - }, - sign_material: None, - }, - ), - ( - "stripped_acacia_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([174, 92, 59]), - }, - sign_material: None, - }, - ), - ( - "stripped_bamboo_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([178, 158, 72]), - }, - sign_material: None, - }, - ), - ( - "stripped_birch_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 171, 116]), - }, - sign_material: None, - }, - ), - ( - "stripped_birch_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([196, 176, 118]), - }, - sign_material: None, - }, - ), - ( - "stripped_cherry_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([221, 164, 157]), - }, - sign_material: None, - }, - ), - ( - "stripped_cherry_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([215, 145, 148]), - }, - sign_material: None, - }, - ), - ( - "stripped_crimson_hyphae", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([137, 57, 90]), - }, - sign_material: None, - }, - ), - ( - "stripped_crimson_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([121, 56, 82]), - }, - sign_material: None, - }, - ), - ( - "stripped_dark_oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([65, 44, 22]), - }, - sign_material: None, - }, - ), - ( - "stripped_dark_oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([72, 56, 36]), - }, - sign_material: None, - }, - ), - ( - "stripped_jungle_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([165, 122, 81]), - }, - sign_material: None, - }, - ), - ( - "stripped_jungle_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([171, 132, 84]), - }, - sign_material: None, - }, - ), - ( - "stripped_mangrove_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 43, 43]), - }, - sign_material: None, - }, - ), - ( - "stripped_mangrove_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([119, 54, 47]), - }, - sign_material: None, - }, - ), - ( - "stripped_oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([160, 129, 77]), - }, - sign_material: None, - }, - ), - ( - "stripped_oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([177, 144, 86]), - }, - sign_material: None, - }, - ), - ( - "stripped_pale_oak_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([235, 226, 225]), - }, - sign_material: None, - }, - ), - ( - "stripped_pale_oak_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([245, 238, 236]), - }, - sign_material: None, - }, - ), - ( - "stripped_spruce_log", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([105, 80, 46]), - }, - sign_material: None, - }, - ), - ( - "stripped_spruce_wood", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([115, 89, 52]), - }, - sign_material: None, - }, - ), - ( - "stripped_warped_hyphae", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([57, 150, 147]), - }, - sign_material: None, - }, - ), - ( - "stripped_warped_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([52, 128, 124]), - }, - sign_material: None, - }, - ), - ( - "structure_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([88, 74, 90]), - }, - sign_material: None, - }, - ), - ( - "structure_void", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "sugar_cane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([148, 192, 101]), - }, - sign_material: None, - }, - ), - ( - "sunflower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([246, 196, 54]), - }, - sign_material: None, - }, - ), - ( - "suspicious_gravel", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([129, 125, 124]), - }, - sign_material: None, - }, - ), - ( - "suspicious_sand", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([217, 204, 159]), - }, - sign_material: None, - }, - ), - ( - "sweet_berry_bush", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([68, 77, 50]), - }, - sign_material: None, - }, - ), - ( - "tall_dry_grass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([196, 171, 122]), - }, - sign_material: None, - }, - ), - ( - "tall_grass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([151, 149, 151]), - }, - sign_material: None, - }, - ), - ( - "tall_seagrass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([59, 139, 14]), - }, - sign_material: None, - }, - ), - ( - "target", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([226, 170, 157]), - }, - sign_material: None, - }, - ), - ( - "terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([152, 94, 67]), - }, - sign_material: None, - }, - ), - ( - "test_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "test_instance_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tinted_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 38, 46]), - }, - sign_material: None, - }, - ), - ( - "tnt", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([142, 62, 53]), - }, - sign_material: None, - }, - ), - ( - "torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "torchflower", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "torchflower_crop", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "trapped_chest", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([162, 130, 78]), - }, - sign_material: None, - }, - ), - ( - "trial_spawner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([56, 82, 98]), - }, - sign_material: None, - }, - ), - ( - "tripwire", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tripwire_hook", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tube_coral", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tube_coral_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([49, 87, 206]), - }, - sign_material: None, - }, - ), - ( - "tube_coral_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tube_coral_wall_fan", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "tuff", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 109, 102]), - }, - sign_material: None, - }, - ), - ( - "tuff_brick_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 102, 95]), - }, - sign_material: None, - }, - ), - ( - "tuff_brick_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 102, 95]), - }, - sign_material: None, - }, - ), - ( - "tuff_brick_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 102, 95]), - }, - sign_material: None, - }, - ), - ( - "tuff_bricks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([98, 102, 95]), - }, - sign_material: None, - }, - ), - ( - "tuff_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 109, 102]), - }, - sign_material: None, - }, - ), - ( - "tuff_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 109, 102]), - }, - sign_material: None, - }, - ), - ( - "tuff_wall", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 109, 102]), - }, - sign_material: None, - }, - ), - ( - "turtle_egg", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([228, 226, 191]), - }, - sign_material: None, - }, - ), - ( - "twisting_vines", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 143, 124]), - }, - sign_material: None, - }, - ), - ( - "twisting_vines_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 135, 122]), - }, - sign_material: None, - }, - ), - ( - "vault", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([54, 69, 79]), - }, - sign_material: None, - }, - ), - ( - "verdant_froglight", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([229, 244, 228]), - }, - sign_material: None, - }, - ), - ( - "vine", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Grass}), - color: Color([116, 116, 116]), - }, - sign_material: None, - }, - ), - ( - "void_air", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("oak"), - }, - ), - ( - "wall_torch", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "warped_button", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "warped_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([44, 126, 120]), - }, - sign_material: None, - }, - ), - ( - "warped_fence", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_fence_gate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_fungus", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "warped_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("warped"), - }, - ), - ( - "warped_hyphae", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([58, 58, 77]), - }, - sign_material: None, - }, - ), - ( - "warped_nylium", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 114, 101]), - }, - sign_material: None, - }, - ), - ( - "warped_planks", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_pressure_plate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_roots", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([20, 138, 124]), - }, - sign_material: None, - }, - ), - ( - "warped_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: Some("warped"), - }, - ), - ( - "warped_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([43, 104, 99]), - }, - sign_material: None, - }, - ), - ( - "warped_stem", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([53, 109, 110]), - }, - sign_material: None, - }, - ), - ( - "warped_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([47, 119, 111]), - }, - sign_material: None, - }, - ), - ( - "warped_wall_hanging_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("warped"), - }, - ), - ( - "warped_wall_sign", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{WallSign}), - color: Color([0, 0, 0]), - }, - sign_material: Some("warped"), - }, - ), - ( - "warped_wart_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([22, 119, 121]), - }, - sign_material: None, - }, - ), - ( - "water", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque|Water}), - color: Color([177, 177, 177]), - }, - sign_material: None, - }, - ), - ( - "water_cauldron", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([73, 72, 74]), - }, - sign_material: None, - }, - ), - ( - "waxed_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([184, 100, 73]), - }, - sign_material: None, - }, - ), - ( - "waxed_copper_block", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 107, 79]), - }, - sign_material: None, - }, - ), - ( - "waxed_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([156, 86, 57]), - }, - sign_material: None, - }, - ), - ( - "waxed_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([192, 109, 82]), - }, - sign_material: None, - }, - ), - ( - "waxed_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 107, 79]), - }, - sign_material: None, - }, - ), - ( - "waxed_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([190, 106, 79]), - }, - sign_material: None, - }, - ), - ( - "waxed_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "waxed_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "waxed_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([191, 106, 80]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 119, 100]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 103]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([135, 107, 89]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([164, 123, 106]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 104]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([161, 125, 104]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "waxed_exposed_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([154, 121, 101]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 161, 132]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 162, 132]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([70, 132, 109]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 160, 132]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([82, 161, 131]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([83, 161, 132]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "waxed_oxidized_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([79, 153, 126]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([104, 150, 111]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 153, 110]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([92, 126, 99]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 150, 109]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 152, 110]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 153, 110]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "waxed_weathered_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "weathered_chiseled_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([104, 150, 111]), - }, - sign_material: None, - }, - ), - ( - "weathered_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 153, 110]), - }, - sign_material: None, - }, - ), - ( - "weathered_copper_bulb", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([92, 126, 99]), - }, - sign_material: None, - }, - ), - ( - "weathered_copper_door", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([110, 150, 109]), - }, - sign_material: None, - }, - ), - ( - "weathered_copper_grate", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([106, 152, 110]), - }, - sign_material: None, - }, - ), - ( - "weathered_copper_trapdoor", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([108, 153, 110]), - }, - sign_material: None, - }, - ), - ( - "weathered_cut_copper", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "weathered_cut_copper_slab", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "weathered_cut_copper_stairs", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([109, 145, 107]), - }, - sign_material: None, - }, - ), - ( - "weeping_vines", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([104, 1, 0]), - }, - sign_material: None, - }, - ), - ( - "weeping_vines_plant", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([132, 16, 12]), - }, - sign_material: None, - }, - ), - ( - "wet_sponge", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([171, 181, 70]), - }, - sign_material: None, - }, - ), - ( - "wheat", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([166, 151, 73]), - }, - sign_material: None, - }, - ), - ( - "white_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "white_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "white_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "white_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "white_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([233, 236, 236]), - }, - sign_material: None, - }, - ), - ( - "white_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([207, 213, 214]), - }, - sign_material: None, - }, - ), - ( - "white_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([225, 227, 227]), - }, - sign_material: None, - }, - ), - ( - "white_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([188, 212, 202]), - }, - sign_material: None, - }, - ), - ( - "white_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([215, 220, 221]), - }, - sign_material: None, - }, - ), - ( - "white_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([255, 255, 255]), - }, - sign_material: None, - }, - ), - ( - "white_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([246, 246, 246]), - }, - sign_material: None, - }, - ), - ( - "white_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([209, 178, 161]), - }, - sign_material: None, - }, - ), - ( - "white_tulip", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "white_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "white_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([233, 236, 236]), - }, - sign_material: None, - }, - ), - ( - "wildflowers", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "wither_rose", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "wither_skeleton_skull", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "wither_skeleton_wall_skull", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "yellow_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "yellow_bed", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "yellow_candle", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "yellow_candle_cake", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 222, 214]), - }, - sign_material: None, - }, - ), - ( - "yellow_carpet", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 197, 39]), - }, - sign_material: None, - }, - ), - ( - "yellow_concrete", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([240, 175, 21]), - }, - sign_material: None, - }, - ), - ( - "yellow_concrete_powder", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([232, 199, 54]), - }, - sign_material: None, - }, - ), - ( - "yellow_glazed_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([234, 192, 88]), - }, - sign_material: None, - }, - ), - ( - "yellow_shulker_box", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 188, 29]), - }, - sign_material: None, - }, - ), - ( - "yellow_stained_glass", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([229, 229, 51]), - }, - sign_material: None, - }, - ), - ( - "yellow_stained_glass_pane", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([221, 221, 48]), - }, - sign_material: None, - }, - ), - ( - "yellow_terracotta", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([186, 133, 35]), - }, - sign_material: None, - }, - ), - ( - "yellow_wall_banner", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "yellow_wool", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{Opaque}), - color: Color([248, 197, 39]), - }, - sign_material: None, - }, - ), - ( - "zombie_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), - ( - "zombie_wall_head", - ConstBlockType { - block_color: BlockColor { - flags: make_bitflags!(BlockFlag::{}), - color: Color([0, 0, 0]), - }, - sign_material: None, - }, - ), -]; diff --git a/crates/resource/src/legacy_biomes.rs b/crates/resource/src/legacy_biomes.rs deleted file mode 100644 index d980823..0000000 --- a/crates/resource/src/legacy_biomes.rs +++ /dev/null @@ -1,202 +0,0 @@ -//! Manually maintained biome data (aliases and legacy biome IDs) - -/// Biome ID aliases -/// -/// Some biomes have been renamed or merged in recent Minecraft versions. -/// Maintain a list of aliases to support chunks saved by older versions. -pub const BIOME_ALIASES: &[(&str, &str)] = &[ - // Biomes fix - ("beaches", "beach"), - ("cold_beach", "snowy_beach"), - ("cold_deep_ocean", "deep_cold_ocean"), - ("extreme_hills", "mountains"), - ("extreme_hills_with_trees", "wooded_mountains"), - ("forest_hills", "wooded_hills"), - ("frozen_deep_ocean", "deep_frozen_ocean"), - ("hell", "nether_wastes"), - ("ice_flats", "snowy_tundra"), - ("ice_mountains", "snowy_mountains"), - ("lukewarm_deep_ocean", "deep_lukewarm_ocean"), - ("mesa", "badlands"), - ("mesa_clear_rock", "badlands_plateau"), - ("mesa_rock", "wooded_badlands_plateau"), - ("mushroom_island", "mushroom_fields"), - ("mushroom_island_shore", "mushroom_field_shore"), - ("mutated_birch_forest", "tall_birch_forest"), - ("mutated_birch_forest_hills", "tall_birch_hills"), - ("mutated_desert", "desert_lakes"), - ("mutated_extreme_hills", "gravelly_mountains"), - ( - "mutated_extreme_hills_with_trees", - "modified_gravelly_mountains", - ), - ("mutated_forest", "flower_forest"), - ("mutated_ice_flats", "ice_spikes"), - ("mutated_jungle", "modified_jungle"), - ("mutated_jungle_edge", "modified_jungle_edge"), - ("mutated_mesa", "eroded_badlands"), - ("mutated_mesa_clear_rock", "modified_badlands_plateau"), - ("mutated_mesa_rock", "modified_wooded_badlands_plateau"), - ("mutated_plains", "sunflower_plains"), - ("mutated_redwood_taiga", "giant_spruce_taiga"), - ("mutated_redwood_taiga_hills", "giant_spruce_taiga_hills"), - ("mutated_roofed_forest", "dark_forest_hills"), - ("mutated_savanna", "shattered_savanna"), - ("mutated_savanna_rock", "shattered_savanna_plateau"), - ("mutated_swampland", "swamp_hills"), - ("mutated_taiga", "taiga_mountains"), - ("mutated_taiga_cold", "snowy_taiga_mountains"), - ("redwood_taiga", "giant_tree_taiga"), - ("redwood_taiga_hills", "giant_tree_taiga_hills"), - ("roofed_forest", "dark_forest"), - ("savanna_rock", "savanna_plateau"), - ("sky", "the_end"), - ("sky_island_barren", "end_barrens"), - ("sky_island_high", "end_highlands"), - ("sky_island_low", "small_end_islands"), - ("sky_island_medium", "end_midlands"), - ("smaller_extreme_hills", "mountain_edge"), - ("stone_beach", "stone_shore"), - ("swampland", "swamp"), - ("taiga_cold", "snowy_taiga"), - ("taiga_cold_hills", "snowy_taiga_hills"), - ("void", "the_void"), - ("warm_deep_ocean", "deep_warm_ocean"), - // Nether biome rename - ("nether", "nether_wastes"), - // Caves and Cliffs biome renames - ("badlands_plateau", "badlands"), - ("bamboo_jungle_hills", "bamboo_jungle"), - ("birch_forest_hills", "birch_forest"), - ("dark_forest_hills", "dark_forest"), - ("desert_hills", "desert"), - ("desert_lakes", "desert"), - ("giant_spruce_taiga", "old_growth_spruce_taiga"), - ("giant_spruce_taiga_hills", "old_growth_spruce_taiga"), - ("giant_tree_taiga", "old_growth_pine_taiga"), - ("giant_tree_taiga_hills", "old_growth_pine_taiga"), - ("gravelly_mountains", "windswept_gravelly_hills"), - ("jungle_edge", "sparse_jungle"), - ("jungle_hills", "jungle"), - ("lofty_peaks", "jagged_peaks"), - ("modified_badlands_plateau", "badlands"), - ("modified_gravelly_mountains", "windswept_gravelly_hills"), - ("modified_jungle", "jungle"), - ("modified_jungle_edge", "sparse_jungle"), - ("modified_wooded_badlands_plateau", "wooded_badlands"), - ("mountain_edge", "windswept_hills"), - ("mountains", "windswept_hills"), - ("mushroom_field_shore", "mushroom_fields"), - ("shattered_savanna", "windswept_savanna"), - ("shattered_savanna_plateau", "windswept_savanna"), - ("snowcapped_peaks", "frozen_peaks"), - ("snowy_mountains", "snowy_plains"), - ("snowy_taiga_hills", "snowy_taiga"), - ("snowy_taiga_mountains", "snowy_taiga"), - ("snowy_tundra", "snowy_plains"), - ("stone_shore", "stony_shore"), - ("swamp_hills", "swamp"), - ("taiga_hills", "taiga"), - ("taiga_mountains", "taiga"), - ("tall_birch_forest", "old_growth_birch_forest"), - ("tall_birch_hills", "old_growth_birch_forest"), - ("wooded_badlands_plateau", "wooded_badlands"), - ("wooded_hills", "forest"), - ("wooded_mountains", "windswept_forest"), - // Remove Deep Warm Ocean - ("deep_warm_ocean", "warm_ocean"), -]; - -/// Maps old numeric biome IDs to new string IDs -pub fn legacy_biome(index: u8) -> &'static str { - match index { - 0 => "ocean", - 1 => "plains", - 2 => "desert", - 3 => "mountains", - 4 => "forest", - 5 => "taiga", - 6 => "swamp", - 7 => "river", - 8 => "nether_wastes", - 9 => "the_end", - 10 => "frozen_ocean", - 11 => "frozen_river", - 12 => "snowy_tundra", - 13 => "snowy_mountains", - 14 => "mushroom_fields", - 15 => "mushroom_field_shore", - 16 => "beach", - 17 => "desert_hills", - 18 => "wooded_hills", - 19 => "taiga_hills", - 20 => "mountain_edge", - 21 => "jungle", - 22 => "jungle_hills", - 23 => "jungle_edge", - 24 => "deep_ocean", - 25 => "stone_shore", - 26 => "snowy_beach", - 27 => "birch_forest", - 28 => "birch_forest_hills", - 29 => "dark_forest", - 30 => "snowy_taiga", - 31 => "snowy_taiga_hills", - 32 => "giant_tree_taiga", - 33 => "giant_tree_taiga_hills", - 34 => "wooded_mountains", - 35 => "savanna", - 36 => "savanna_plateau", - 37 => "badlands", - 38 => "wooded_badlands_plateau", - 39 => "badlands_plateau", - 40 => "small_end_islands", - 41 => "end_midlands", - 42 => "end_highlands", - 43 => "end_barrens", - 44 => "warm_ocean", - 45 => "lukewarm_ocean", - 46 => "cold_ocean", - 47 => "deep_warm_ocean", - 48 => "deep_lukewarm_ocean", - 49 => "deep_cold_ocean", - 50 => "deep_frozen_ocean", - 127 => "the_void", - 129 => "sunflower_plains", - 130 => "desert_lakes", - 131 => "gravelly_mountains", - 132 => "flower_forest", - 133 => "taiga_mountains", - 134 => "swamp_hills", - 140 => "ice_spikes", - 149 => "modified_jungle", - 151 => "modified_jungle_edge", - 155 => "tall_birch_forest", - 156 => "tall_birch_hills", - 157 => "dark_forest_hills", - 158 => "snowy_taiga_mountains", - 160 => "giant_spruce_taiga", - 161 => "giant_spruce_taiga_hills", - 162 => "modified_gravelly_mountains", - 163 => "shattered_savanna", - 164 => "shattered_savanna_plateau", - 165 => "eroded_badlands", - 166 => "modified_wooded_badlands_plateau", - 167 => "modified_badlands_plateau", - 168 => "bamboo_jungle", - 169 => "bamboo_jungle_hills", - 170 => "soul_sand_valley", - 171 => "crimson_forest", - 172 => "warped_forest", - 173 => "basalt_deltas", - 174 => "dripstone_caves", - 175 => "lush_caves", - 177 => "meadow", - 178 => "grove", - 179 => "snowy_slopes", - 180 => "snowcapped_peaks", - 181 => "lofty_peaks", - 182 => "stony_peaks", - _ => "ocean", - } -} diff --git a/crates/resource/src/legacy_block_types.rs b/crates/resource/src/legacy_block_types.rs deleted file mode 100644 index 0c4814d..0000000 --- a/crates/resource/src/legacy_block_types.rs +++ /dev/null @@ -1,1027 +0,0 @@ -//! Mapping of old numeric block type and damage/subtype IDs to new string IDs - -/// Helper for block types that don't use the damage/subtype data -const fn simple(id: &str) -> [&str; 16] { - [ - id, id, id, id, id, id, id, id, id, id, id, id, id, id, id, id, - ] -} - -/// Default block type for unassigned numeric IDs -const DEF: &str = "air"; -/// Default entry for block type numbers that are unassigned regardless of subtype -const EMPTY: [&str; 16] = simple(DEF); - -/// Mapping from each numeric block type and damage/subtype ID to new string ID -#[allow(clippy::large_const_arrays)] -pub const LEGACY_BLOCK_TYPES: [[&str; 16]; 256] = [ - /* 0 */ - simple("air"), - /* 1 */ - [ - "stone", - "granite", - "polished_granite", - "diorite", - "polished_diorite", - "andesite", - "polished_andesite", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 2 */ - simple("grass_block"), - /* 3 */ - [ - "dirt", - "coarse_dirt", - "podzol", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 4 */ - simple("cobblestone"), - /* 5 */ - [ - "oak_planks", - "spruce_planks", - "birch_planks", - "jungle_planks", - "acacia_planks", - "dark_oak_planks", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 6 */ - [ - "oak_sapling", - "spruce_sapling", - "birch_sapling", - "jungle_sapling", - "acacia_sapling", - "dark_oak_sapling", - DEF, - DEF, - "oak_sapling", - "spruce_sapling", - "birch_sapling", - "jungle_sapling", - "acacia_sapling", - "dark_oak_sapling", - DEF, - DEF, - ], - /* 7 */ - simple("bedrock"), - /* 8 */ - simple("water"), - /* 9 */ - simple("water"), - /* 10 */ - simple("lava"), - /* 11 */ - simple("lava"), - /* 12 */ - [ - "sand", "red_sand", DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, - ], - /* 13 */ - simple("gravel"), - /* 14 */ - simple("gold_ore"), - /* 15 */ - simple("iron_ore"), - /* 16 */ - simple("coal_ore"), - /* 17 */ - [ - "oak_log", - "spruce_log", - "birch_log", - "jungle_log", - "oak_log", - "spruce_log", - "birch_log", - "jungle_log", - "oak_log", - "spruce_log", - "birch_log", - "jungle_log", - "oak_log", - "spruce_log", - "birch_log", - "jungle_log", - ], - /* 18 */ - [ - "oak_leaves", - "spruce_leaves", - "birch_leaves", - "jungle_leaves", - "oak_leaves", - "spruce_leaves", - "birch_leaves", - "jungle_leaves", - "oak_leaves", - "spruce_leaves", - "birch_leaves", - "jungle_leaves", - "oak_leaves", - "spruce_leaves", - "birch_leaves", - "jungle_leaves", - ], - /* 19 */ - simple("sponge"), - /* 20 */ - simple("glass"), - /* 21 */ - simple("lapis_ore"), - /* 22 */ - simple("lapis_block"), - /* 23 */ - simple("dispenser"), - /* 24 */ - simple("sandstone"), - /* 25 */ - simple("note_block"), - /* 26 */ - EMPTY, // bed - /* 27 */ - simple("powered_rail"), - /* 28 */ - simple("detector_rail"), - /* 29 */ - simple("sticky_piston"), - /* 30 */ - simple("cobweb"), - /* 31 */ - [ - "grass", "fern", DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, DEF, - ], - /* 32 */ - simple("dead_bush"), - /* 33 */ - simple("piston"), - /* 34 */ - simple("piston_head"), - /* 35 */ - [ - "white_wool", - "orange_wool", - "magenta_wool", - "light_blue_wool", - "yellow_wool", - "lime_wool", - "pink_wool", - "gray_wool", - "light_gray_wool", - "cyan_wool", - "purple_wool", - "blue_wool", - "brown_wool", - "green_wool", - "red_wool", - "black_wool", - ], - /* 36 */ - simple("moving_piston"), - /* 37 */ - simple("dandelion"), - /* 38 */ - [ - "poppy", - "blue_orchid", - "allium", - "azure_bluet", - "red_tulip", - "orange_tulip", - "white_tulip", - "pink_tulip", - "oxeye_daisy", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 39 */ - simple("brown_mushroom"), - /* 40 */ - simple("red_mushroom"), - /* 41 */ - simple("gold_block"), - /* 42 */ - simple("iron_block"), - /* 43 */ - [ - "smooth_stone_slab", - "sandstone_slab", - "oak_slab", - "cobblestone_slab", - "brick_slab", - "stone_brick_slab", - "nether_brick_slab", - "quartz_slab", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 44 */ - [ - "smooth_stone_slab", - "sandstone_slab", - "oak_slab", - "cobblestone_slab", - "brick_slab", - "stone_brick_slab", - "nether_brick_slab", - "quartz_slab", - "stone_slab", - "sandstone_slab", - "oak_slab", - "cobblestone_slab", - "brick_slab", - "stone_brick_slab", - "nether_brick_slab", - "quartz_slab", - ], - /* 45 */ - simple("bricks"), - /* 46 */ - simple("tnt"), - /* 47 */ - simple("bookshelf"), - /* 48 */ - simple("mossy_cobblestone"), - /* 49 */ - simple("obsidian"), - /* 50 */ - [ - DEF, - "wall_torch", - "wall_torch", - "wall_torch", - "wall_torch", - "torch", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 51 */ - simple("fire"), - /* 52 */ - simple("spawner"), - /* 53 */ - simple("oak_stairs"), - /* 54 */ - simple("chest"), - /* 55 */ - simple("redstone_wire"), - /* 56 */ - simple("diamond_ore"), - /* 57 */ - simple("diamond_block"), - /* 58 */ - simple("crafting_table"), - /* 59 */ - simple("wheat"), - /* 60 */ - simple("farmland"), - /* 61 */ - simple("furnace"), - /* 62 */ - simple("furnace"), - /* 63 */ - simple("sign"), - /* 64 */ - simple("oak_door"), - /* 65 */ - simple("ladder"), - /* 66 */ - simple("rail"), - /* 67 */ - simple("cobblestone_stairs"), - /* 68 */ - simple("wall_sign"), - /* 69 */ - simple("lever"), - /* 70 */ - simple("stone_pressure_plate"), - /* 71 */ - simple("iron_door"), - /* 72 */ - simple("oak_pressure_plate"), - /* 73 */ - simple("redstone_ore"), - /* 74 */ - simple("redstone_ore"), - /* 75 */ - [ - DEF, - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_torch", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 76 */ - [ - DEF, - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_wall_torch", - "redstone_torch", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 77 */ - simple("stone_button"), - /* 78 */ - simple("snow"), - /* 79 */ - simple("ice"), - /* 80 */ - simple("snow_block"), - /* 81 */ - simple("cactus"), - /* 82 */ - simple("clay"), - /* 83 */ - simple("sugar_cane"), - /* 84 */ - simple("jukebox"), - /* 85 */ - simple("oak_fence"), - /* 86 */ - simple("pumpkin"), - /* 87 */ - simple("netherrack"), - /* 88 */ - simple("soul_sand"), - /* 89 */ - simple("glowstone"), - /* 90 */ - simple("nether_portal"), - /* 91 */ - simple("pumpkin"), - /* 92 */ - simple("cake"), - /* 93 */ - simple("repeater"), - /* 94 */ - simple("repeater"), - /* 95 */ - [ - "white_stained_glass", - "orange_stained_glass", - "magenta_stained_glass", - "light_blue_stained_glass", - "yellow_stained_glass", - "lime_stained_glass", - "pink_stained_glass", - "gray_stained_glass", - "light_gray_stained_glass", - "cyan_stained_glass", - "purple_stained_glass", - "blue_stained_glass", - "brown_stained_glass", - "green_stained_glass", - "red_stained_glass", - "black_stained_glass", - ], - /* 96 */ - simple("oak_trapdoor"), - /* 97 */ - [ - "infested_stone", - "infested_cobblestone", - "infested_stone_bricks", - "infested_mossy_stone_bricks", - "infested_cracked_stone_bricks", - "infested_chiseled_stone_bricks", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 98 */ - [ - "stone_bricks", - "mossy_stone_bricks", - "cracked_stone_bricks", - "chiseled_stone_bricks", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 99 */ - simple("brown_mushroom_block"), - /* 100 */ - simple("red_mushroom_block"), - /* 101 */ - simple("iron_bars"), - /* 102 */ - simple("glass_pane"), - /* 103 */ - simple("melon"), - /* 104 */ - simple("pumpkin_stem"), - /* 105 */ - simple("melon_stem"), - /* 106 */ - simple("vine"), - /* 107 */ - simple("oak_fence_gate"), - /* 108 */ - simple("brick_stairs"), - /* 109 */ - simple("stone_brick_stairs"), - /* 110 */ - simple("mycelium"), - /* 111 */ - simple("lily_pad"), - /* 112 */ - simple("nether_bricks"), - /* 113 */ - simple("nether_brick_fence"), - /* 114 */ - simple("nether_brick_stairs"), - /* 115 */ - simple("nether_wart"), - /* 116 */ - simple("enchanting_table"), - /* 117 */ - simple("brewing_stand"), - /* 118 */ - simple("cauldron"), - /* 119 */ - simple("end_portal"), - /* 120 */ - simple("end_portal_frame"), - /* 121 */ - simple("end_stone"), - /* 122 */ - simple("dragon_egg"), - /* 123 */ - simple("redstone_lamp"), - /* 124 */ - simple("redstone_lamp"), - /* 125 */ - [ - "oak_slab", - "spruce_slab", - "birch_slab", - "jungle_slab", - "acacia_slab", - "dark_oak_slab", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 126 */ - [ - "oak_slab", - "spruce_slab", - "birch_slab", - "jungle_slab", - "acacia_slab", - "dark_oak_slab", - DEF, - DEF, - "oak_slab", - "spruce_slab", - "birch_slab", - "jungle_slab", - "acacia_slab", - "dark_oak_slab", - DEF, - DEF, - ], - /* 127 */ - simple("cocoa"), - /* 128 */ - simple("sandstone_stairs"), - /* 129 */ - simple("emerald_ore"), - /* 130 */ - simple("ender_chest"), - /* 131 */ - simple("tripwire_hook"), - /* 132 */ - simple("tripwire"), - /* 133 */ - simple("emerald_block"), - /* 134 */ - simple("spruce_stairs"), - /* 135 */ - simple("birch_stairs"), - /* 136 */ - simple("jungle_stairs"), - /* 137 */ - simple("command_block"), - /* 138 */ - simple("beacon"), - /* 139 */ - [ - "cobblestone_wall", - "mossy_cobblestone_wall", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 140 */ - simple("flower_pot"), - /* 141 */ - simple("carrots"), - /* 142 */ - simple("potatoes"), - /* 143 */ - EMPTY, - /* 144 */ - EMPTY, - /* 145 */ - [ - "anvil", - "anvil", - "anvil", - "anvil", - "chipped_anvil", - "chipped_anvil", - "chipped_anvil", - "chipped_anvil", - "damaged_anvil", - "damaged_anvil", - "damaged_anvil", - "damaged_anvil", - DEF, - DEF, - DEF, - DEF, - ], - /* 146 */ - simple("trapped_chest"), - /* 147 */ - simple("light_weighted_pressure_plate"), - /* 148 */ - simple("heavy_weighted_pressure_plate"), - /* 149 */ - simple("comparator"), - /* 150 */ - simple("comparator"), - /* 151 */ - simple("daylight_detector"), - /* 152 */ - simple("redstone_block"), - /* 153 */ - simple("nether_quartz_ore"), - /* 154 */ - simple("hopper"), - /* 155 */ - simple("quartz_block"), - /* 156 */ - simple("quartz_stairs"), - /* 157 */ - simple("activator_rail"), - /* 158 */ - simple("dropper"), - /* 159 */ - [ - "white_terracotta", - "orange_terracotta", - "magenta_terracotta", - "light_blue_terracotta", - "yellow_terracotta", - "lime_terracotta", - "pink_terracotta", - "gray_terracotta", - "light_gray_terracotta", - "cyan_terracotta", - "purple_terracotta", - "blue_terracotta", - "brown_terracotta", - "green_terracotta", - "red_terracotta", - "black_terracotta", - ], - /* 160 */ - [ - "white_stained_glass_pane", - "orange_stained_glass_pane", - "magenta_stained_glass_pane", - "light_blue_stained_glass_pane", - "yellow_stained_glass_pane", - "lime_stained_glass_pane", - "pink_stained_glass_pane", - "gray_stained_glass_pane", - "light_gray_stained_glass_pane", - "cyan_stained_glass_pane", - "purple_stained_glass_pane", - "blue_stained_glass_pane", - "brown_stained_glass_pane", - "green_stained_glass_pane", - "red_stained_glass_pane", - "black_stained_glass_pane", - ], - /* 161 */ - [ - "acacia_leaves", - "dark_oak_leaves", - DEF, - DEF, - "acacia_leaves", - "dark_oak_leaves", - DEF, - DEF, - "acacia_leaves", - "dark_oak_leaves", - DEF, - DEF, - "acacia_leaves", - "dark_oak_leaves", - DEF, - DEF, - ], - /* 162 */ - [ - "acacia_log", - "dark_oak_log", - DEF, - DEF, - "acacia_log", - "dark_oak_log", - DEF, - DEF, - "acacia_log", - "dark_oak_log", - DEF, - DEF, - "acacia_log", - "dark_oak_log", - DEF, - DEF, - ], - /* 163 */ - simple("acacia_stairs"), - /* 164 */ - simple("dark_oak_stairs"), - /* 165 */ - simple("slime_block"), - /* 166 */ - simple("barrier"), - /* 167 */ - simple("iron_trapdoor"), - /* 168 */ - [ - "prismarine", - "prismarine_bricks", - "dark_prismarine", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 169 */ - simple("sea_lantern"), - /* 170 */ - simple("hay_block"), - /* 171 */ - [ - "white_carpet", - "orange_carpet", - "magenta_carpet", - "light_blue_carpet", - "yellow_carpet", - "lime_carpet", - "pink_carpet", - "gray_carpet", - "light_gray_carpet", - "cyan_carpet", - "purple_carpet", - "blue_carpet", - "brown_carpet", - "green_carpet", - "red_carpet", - "black_carpet", - ], - /* 172 */ - simple("terracotta"), - /* 173 */ - simple("coal_block"), - /* 174 */ - simple("packed_ice"), - /* 175 */ - [ - "sunflower", - "lilac", - "tall_grass", - "large_fern", - "rose_bush", - "peony", - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - DEF, - ], - /* 176 */ - EMPTY, // banner - /* 177 */ - EMPTY, // wall banner - /* 178 */ - simple("daylight_detector"), - /* 179 */ - simple("red_sandstone"), - /* 180 */ - simple("red_sandstone_stairs"), - /* 181 */ - simple("red_sandstone_slab"), - /* 182 */ - simple("red_sandstone_slab"), - /* 183 */ - simple("spruce_fence_gate"), - /* 184 */ - simple("birch_fence_gate"), - /* 185 */ - simple("jungle_fence_gate"), - /* 186 */ - simple("dark_oak_fence_gate"), - /* 187 */ - simple("acacia_fence_gate"), - /* 188 */ - simple("spruce_fence"), - /* 189 */ - simple("birch_fence"), - /* 190 */ - simple("jungle_fence"), - /* 191 */ - simple("dark_oak_fence"), - /* 192 */ - simple("acacia_fence"), - /* 193 */ - simple("spruce_door"), - /* 194 */ - simple("birch_door"), - /* 195 */ - simple("jungle_door"), - /* 196 */ - simple("acacia_door"), - /* 197 */ - simple("dark_oak_door"), - /* 198 */ - simple("end_rod"), - /* 199 */ - simple("chorus_plant"), - /* 200 */ - simple("chorus_flower"), - /* 201 */ - simple("purpur_block"), - /* 202 */ - simple("purpur_pillar"), - /* 203 */ - simple("purpur_stairs"), - /* 204 */ - simple("purpur_slab"), - /* 205 */ - simple("purpur_slab"), - /* 206 */ - simple("end_stone_bricks"), - /* 207 */ - simple("beetroots"), - /* 208 */ - simple("grass_path"), - /* 209 */ - simple("end_gateway"), - /* 210 */ - simple("repeating_command_block"), - /* 211 */ - simple("chain_command_block"), - /* 212 */ - simple("frosted_ice"), - /* 213 */ - simple("magma_block"), - /* 214 */ - simple("nether_wart_block"), - /* 215 */ - simple("red_nether_bricks"), - /* 216 */ - simple("bone_block"), - /* 217 */ - simple("structure_void"), - /* 218 */ - simple("observer"), - /* 219 */ - simple("white_shulker_box"), - /* 220 */ - simple("orange_shulker_box"), - /* 221 */ - simple("magenta_shulker_box"), - /* 222 */ - simple("light_blue_shulker_box"), - /* 223 */ - simple("yellow_shulker_box"), - /* 224 */ - simple("lime_shulker_box"), - /* 225 */ - simple("pink_shulker_box"), - /* 226 */ - simple("gray_shulker_box"), - /* 227 */ - simple("light_gray_shulker_box"), - /* 228 */ - simple("cyan_shulker_box"), - /* 229 */ - simple("purple_shulker_box"), - /* 230 */ - simple("blue_shulker_box"), - /* 231 */ - simple("brown_shulker_box"), - /* 232 */ - simple("green_shulker_box"), - /* 233 */ - simple("red_shulker_box"), - /* 234 */ - simple("black_shulker_box"), - /* 235 */ - simple("white_glazed_terracotta"), - /* 236 */ - simple("orange_glazed_terracotta"), - /* 237 */ - simple("magenta_glazed_terracotta"), - /* 238 */ - simple("light_blue_glazed_terracotta"), - /* 239 */ - simple("yellow_glazed_terracotta"), - /* 240 */ - simple("lime_glazed_terracotta"), - /* 241 */ - simple("pink_glazed_terracotta"), - /* 242 */ - simple("gray_glazed_terracotta"), - /* 243 */ - simple("light_gray_glazed_terracotta"), - /* 244 */ - simple("cyan_glazed_terracotta"), - /* 245 */ - simple("purple_glazed_terracotta"), - /* 246 */ - simple("blue_glazed_terracotta"), - /* 247 */ - simple("brown_glazed_terracotta"), - /* 248 */ - simple("green_glazed_terracotta"), - /* 249 */ - simple("red_glazed_terracotta"), - /* 250 */ - simple("black_glazed_terracotta"), - /* 251 */ - [ - "white_concrete", - "orange_concrete", - "magenta_concrete", - "light_blue_concrete", - "yellow_concrete", - "lime_concrete", - "pink_concrete", - "gray_concrete", - "light_gray_concrete", - "cyan_concrete", - "purple_concrete", - "blue_concrete", - "brown_concrete", - "green_concrete", - "red_concrete", - "black_concrete", - ], - /* 252 */ - [ - "white_concrete_powder", - "orange_concrete_powder", - "magenta_concrete_powder", - "light_blue_concrete_powder", - "yellow_concrete_powder", - "lime_concrete_powder", - "pink_concrete_powder", - "gray_concrete_powder", - "light_gray_concrete_powder", - "cyan_concrete_powder", - "purple_concrete_powder", - "blue_concrete_powder", - "brown_concrete_powder", - "green_concrete_powder", - "red_concrete_powder", - "black_concrete_powder", - ], - /* 253 */ - EMPTY, - /* 254 */ - EMPTY, - /* 255 */ - simple("structure_block"), -]; diff --git a/crates/resource/src/lib.rs b/crates/resource/src/lib.rs deleted file mode 100644 index 86cfb0f..0000000 --- a/crates/resource/src/lib.rs +++ /dev/null @@ -1,344 +0,0 @@ -#![doc = env!("CARGO_PKG_DESCRIPTION")] -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -mod biomes; -mod block_color; -mod block_types; -mod legacy_biomes; -mod legacy_block_types; - -use std::collections::HashMap; - -use bincode::{BorrowDecode, Decode, Encode}; -use enumflags2::{BitFlags, bitflags}; - -/// Flags describing special properties of [BlockType]s -#[bitflags] -#[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum BlockFlag { - /// The block type is opaque - Opaque, - /// The block type is colored using biome grass colors - Grass, - /// The block type is colored using biome foliage colors - Foliage, - /// The block type is birch foliage - Birch, - /// The block type is spruce foliage - Spruce, - /// The block type is colored using biome water colors - Water, - /// The block type is a wall sign - /// - /// The WallSign flag is used to distinguish wall signs from - /// freestanding or -hanging signs. - WallSign, -} - -/// An RGB color with u8 components -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Encode, Decode)] -pub struct Color(pub [u8; 3]); - -/// An RGB color with f32 components -pub type Colorf = glam::Vec3; - -/// A block type specification -#[derive(Debug, Clone, Copy)] -pub struct BlockColor { - /// Bit set of [BlockFlag]s describing special properties of the block type - pub flags: BitFlags, - /// Base color of the block type - pub color: Color, -} - -impl BlockColor { - /// Checks whether a block color has a given [BlockFlag] set - #[inline] - pub fn is(&self, flag: BlockFlag) -> bool { - self.flags.contains(flag) - } -} - -impl Encode for BlockColor { - fn encode( - &self, - encoder: &mut E, - ) -> Result<(), bincode::error::EncodeError> { - bincode::Encode::encode(&self.flags.bits(), encoder)?; - bincode::Encode::encode(&self.color, encoder)?; - Ok(()) - } -} - -impl Decode for BlockColor { - fn decode>( - decoder: &mut D, - ) -> Result { - Ok(BlockColor { - flags: BitFlags::from_bits(bincode::Decode::decode(decoder)?).or(Err( - bincode::error::DecodeError::Other("invalid block flags"), - ))?, - color: bincode::Decode::decode(decoder)?, - }) - } -} - -impl<'de, Context> BorrowDecode<'de, Context> for BlockColor { - fn borrow_decode>( - decoder: &mut D, - ) -> Result { - Ok(BlockColor { - flags: BitFlags::from_bits(bincode::BorrowDecode::borrow_decode(decoder)?).or(Err( - bincode::error::DecodeError::Other("invalid block flags"), - ))?, - color: bincode::BorrowDecode::borrow_decode(decoder)?, - }) - } -} - -/// A block type specification (for use in constants) -#[derive(Debug, Clone)] -struct ConstBlockType { - /// Determines the rendered color of the block type - pub block_color: BlockColor, - /// Material of a sign block - pub sign_material: Option<&'static str>, -} - -/// A block type specification -#[derive(Debug, Clone)] -pub struct BlockType { - /// Determines the rendered color of the block type - pub block_color: BlockColor, - /// Material of a sign block - pub sign_material: Option, -} - -impl From<&ConstBlockType> for BlockType { - fn from(value: &ConstBlockType) -> Self { - BlockType { - block_color: value.block_color, - sign_material: value.sign_material.map(String::from), - } - } -} - -/// Used to look up standard Minecraft block types -#[derive(Debug)] -pub struct BlockTypes { - /// Map of string IDs to block types - block_type_map: HashMap, - /// Array used to look up old numeric block type and subtype values - legacy_block_types: Box<[[BlockType; 16]; 256]>, -} - -impl Default for BlockTypes { - fn default() -> Self { - let block_type_map: HashMap<_, _> = block_types::BLOCK_TYPES - .iter() - .map(|(k, v)| (String::from(*k), BlockType::from(v))) - .collect(); - let legacy_block_types = Box::new(legacy_block_types::LEGACY_BLOCK_TYPES.map(|inner| { - inner.map(|id| { - block_type_map - .get(id) - .expect("Unknown legacy block type") - .clone() - }) - })); - - BlockTypes { - block_type_map, - legacy_block_types, - } - } -} - -impl BlockTypes { - /// Resolves a Minecraft 1.13+ string block type ID - #[inline] - pub fn get(&self, id: &str) -> Option<&BlockType> { - let suffix = id.strip_prefix("minecraft:")?; - self.block_type_map.get(suffix) - } - - /// Resolves a Minecraft pre-1.13 numeric block type ID - #[inline] - pub fn get_legacy(&self, id: u8, data: u8) -> Option<&BlockType> { - Some(&self.legacy_block_types[id as usize][data as usize]) - } -} - -pub use block_color::{block_color, needs_biome}; - -/// Grass color modifier used by a biome -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -pub enum BiomeGrassColorModifier { - /// Grass color modifier used by the dark forest biome - DarkForest, - /// Grass color modifier used by swamp biomes - Swamp, -} - -/// A biome specification -/// -/// A Biome contains all information about a biome necessary to compute a block -/// color given a block type and depth -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Encode, Decode)] -pub struct Biome { - /// Temperature value - /// - /// For more efficient storage, the temperature is stored as an integer - /// after mutiplying the raw value by 20 - pub temp: i8, - /// Downfall value - /// - /// For more efficient storage, the downfall is stored as an integer - /// after mutiplying the raw value by 20 - pub downfall: i8, - /// Water color override - pub water_color: Option, - /// Foliage color override - pub foliage_color: Option, - /// Grass color override - pub grass_color: Option, - /// Grass color modifier - pub grass_color_modifier: Option, -} - -impl Biome { - /// Constructs a new Biome - const fn new(temp: i16, downfall: i16) -> Biome { - /// Helper to encode temperature and downfall values - /// - /// Converts temperatue and downfall from the input format - /// (mutiplied by 100) to i8 range for more efficient storage. - const fn encode(v: i16) -> i8 { - (v / 5) as i8 - } - Biome { - temp: encode(temp), - downfall: encode(downfall), - grass_color_modifier: None, - water_color: None, - foliage_color: None, - grass_color: None, - } - } - - /// Builder function to override the biome water color - const fn water(self, water_color: [u8; 3]) -> Biome { - Biome { - water_color: Some(Color(water_color)), - ..self - } - } - - /// Builder function to override the biome foliage color - const fn foliage(self, foliage_color: [u8; 3]) -> Biome { - Biome { - foliage_color: Some(Color(foliage_color)), - ..self - } - } - - /// Builder function to override the biome grass color - const fn grass(self, grass_color: [u8; 3]) -> Biome { - Biome { - grass_color: Some(Color(grass_color)), - ..self - } - } - - /// Builder function to set a grass color modifier - const fn modify(self, grass_color_modifier: BiomeGrassColorModifier) -> Biome { - Biome { - grass_color_modifier: Some(grass_color_modifier), - ..self - } - } - - /// Decodes a temperature or downfall value from the storage format to - /// f32 for further calculation - fn decode(val: i8) -> f32 { - f32::from(val) / 20.0 - } - - /// Returns the biome's temperature decoded to its original float value - pub fn temp(&self) -> f32 { - Self::decode(self.temp) - } - - /// Returns the biome's downfall decoded to its original float value - pub fn downfall(&self) -> f32 { - Self::decode(self.downfall) - } -} - -/// Used to look up standard Minecraft biome types -#[derive(Debug)] -pub struct BiomeTypes { - /// Map of string IDs to biome types - biome_map: HashMap, - /// Array used to look up old numeric biome IDs - legacy_biomes: Box<[&'static Biome; 256]>, - /// Fallback for unknown (new/modded) biomes - fallback_biome: &'static Biome, -} - -impl Default for BiomeTypes { - fn default() -> Self { - let mut biome_map: HashMap<_, _> = biomes::BIOMES - .iter() - .map(|(k, v)| (String::from(*k), v)) - .collect(); - - for &(old, new) in legacy_biomes::BIOME_ALIASES.iter().rev() { - let biome = biome_map - .get(new) - .copied() - .expect("Biome alias for unknown biome"); - assert!(biome_map.insert(String::from(old), biome).is_none()); - } - - let legacy_biomes = (0..=255) - .map(|index| { - let id = legacy_biomes::legacy_biome(index); - *biome_map.get(id).expect("Unknown legacy biome") - }) - .collect::>() - .try_into() - .unwrap(); - - let fallback_biome = *biome_map.get("plains").expect("Plains biome undefined"); - - Self { - biome_map, - legacy_biomes, - fallback_biome, - } - } -} - -impl BiomeTypes { - /// Resolves a Minecraft 1.18+ string biome type ID - #[inline] - pub fn get(&self, id: &str) -> Option<&Biome> { - let suffix = id.strip_prefix("minecraft:")?; - self.biome_map.get(suffix).copied() - } - - /// Resolves a Minecraft pre-1.18 numeric biome type ID - #[inline] - pub fn get_legacy(&self, id: u8) -> Option<&Biome> { - Some(self.legacy_biomes[id as usize]) - } - - /// Returns the fallback for unknown (new/modded) biomes - #[inline] - pub fn get_fallback(&self) -> &Biome { - self.fallback_biome - } -} diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml deleted file mode 100644 index 34caa1c..0000000 --- a/crates/types/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "minedmap-types" -version = "0.2.0" -description = "Common types used by several MinedMap crates" -edition.workspace = true -license.workspace = true -readme.workspace = true -repository.workspace = true - -[dependencies] -bincode = "2.0.1" -itertools = "0.14.0" diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs deleted file mode 100644 index f2dc0e1..0000000 --- a/crates/types/src/lib.rs +++ /dev/null @@ -1,236 +0,0 @@ -#![doc = env!("CARGO_PKG_DESCRIPTION")] -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -use std::{ - fmt::Debug, - iter::FusedIterator, - ops::{Index, IndexMut}, -}; - -use bincode::{Decode, Encode}; -use itertools::iproduct; - -/// Const generic AXIS arguments for coordinate types -pub mod axis { - /// The X axis - pub const X: u8 = 0; - /// The Y axis (height) - pub const Y: u8 = 1; - /// The Z axis - pub const Z: u8 = 2; -} - -/// Generates a generic coordinate type with a given range -macro_rules! coord_type { - ($t:ident, $max:expr, $doc:expr $(,)?) => { - #[doc = $doc] - #[derive(Debug, Clone, Copy, PartialEq, Eq)] - pub struct $t(pub u8); - - impl $t { - const MAX: usize = $max; - - /// Constructs a new value - /// - /// Will panic if the value is not in the valid range - #[inline] - pub fn new>(value: T) -> Self { - Self( - value - .try_into() - .ok() - .filter(|&v| (v as usize) < Self::MAX) - .expect("coordinate should be in the valid range"), - ) - } - - /// Returns an iterator over all possible values of the type - #[inline] - pub fn iter() -> impl DoubleEndedIterator> - + ExactSizeIterator - + FusedIterator - + Clone - + Debug { - (0..Self::MAX as u8).map($t) - } - } - }; -} - -/// Number of bits required to store a block coordinate -pub const BLOCK_BITS: u8 = 4; -/// Number of blocks per chunk in each dimension -pub const BLOCKS_PER_CHUNK: usize = 1 << BLOCK_BITS; -coord_type!( - BlockCoord, - BLOCKS_PER_CHUNK, - "A block coordinate relative to a chunk", -); - -/// A block X coordinate relative to a chunk -pub type BlockX = BlockCoord<{ axis::X }>; - -/// A block Y coordinate relative to a chunk section -pub type BlockY = BlockCoord<{ axis::Y }>; - -/// A block Z coordinate relative to a chunk -pub type BlockZ = BlockCoord<{ axis::Z }>; - -/// X and Z coordinates of a block in a chunk -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct LayerBlockCoords { - /// The X coordinate - pub x: BlockX, - /// The Z coordinate - pub z: BlockZ, -} - -impl Debug for LayerBlockCoords { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({}, {})", self.x.0, self.z.0) - } -} - -impl LayerBlockCoords { - /// Computes a block's offset in various data structures - /// - /// Many chunk data structures store block and biome data in the same - /// order. This method computes the offset at which the data for the - /// block at a given coordinate is stored. - #[inline] - pub fn offset(&self) -> usize { - use BLOCKS_PER_CHUNK as N; - let x = self.x.0 as usize; - let z = self.z.0 as usize; - N * z + x - } -} - -/// Generic array for data stored per block of a chunk layer -/// -/// Includes various convenient iteration functions. -#[derive(Debug, Clone, Copy, Default, Encode, Decode)] -pub struct LayerBlockArray(pub [[T; BLOCKS_PER_CHUNK]; BLOCKS_PER_CHUNK]); - -impl Index for LayerBlockArray { - type Output = T; - - #[inline] - fn index(&self, index: LayerBlockCoords) -> &Self::Output { - &self.0[index.z.0 as usize][index.x.0 as usize] - } -} - -impl IndexMut for LayerBlockArray { - #[inline] - fn index_mut(&mut self, index: LayerBlockCoords) -> &mut Self::Output { - &mut self.0[index.z.0 as usize][index.x.0 as usize] - } -} - -/// X, Y and Z coordinates of a block in a chunk section -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct SectionBlockCoords { - /// The X and Z coordinates - pub xz: LayerBlockCoords, - /// The Y coordinate - pub y: BlockY, -} - -impl SectionBlockCoords { - /// Computes a block's offset in various data structures - /// - /// Many chunk data structures store block and biome data in the same - /// order. This method computes the offset at which the data for the - /// block at a given coordinate is stored. - #[inline] - pub fn offset(&self) -> usize { - use BLOCKS_PER_CHUNK as N; - let y = self.y.0 as usize; - N * N * y + self.xz.offset() - } -} - -impl Debug for SectionBlockCoords { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({}, {}, {})", self.xz.x.0, self.y.0, self.xz.z.0) - } -} - -/// A section Y coordinate -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct SectionY(pub i32); - -/// Number of bits required to store a chunk coordinate -pub const CHUNK_BITS: u8 = 5; -/// Number of chunks per region in each dimension -pub const CHUNKS_PER_REGION: usize = 1 << CHUNK_BITS; -coord_type!( - ChunkCoord, - CHUNKS_PER_REGION, - "A chunk coordinate relative to a region", -); - -/// A chunk X coordinate relative to a region -pub type ChunkX = ChunkCoord<{ axis::X }>; - -/// A chunk Z coordinate relative to a region -pub type ChunkZ = ChunkCoord<{ axis::Z }>; - -/// A pair of chunk coordinates relative to a region -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct ChunkCoords { - /// The X coordinate - pub x: ChunkX, - /// The Z coordinate - pub z: ChunkZ, -} - -impl Debug for ChunkCoords { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({}, {})", self.x.0, self.z.0) - } -} - -/// Generic array for data stored per chunk of a region -/// -/// Includes various convenient iteration functions. -#[derive(Debug, Clone, Copy, Default, Encode, Decode)] -pub struct ChunkArray(pub [[T; CHUNKS_PER_REGION]; CHUNKS_PER_REGION]); - -impl ChunkArray { - /// Iterates over all possible chunk coordinate pairs used as [ChunkArray] keys - #[inline] - pub fn keys() -> impl Iterator + Clone + Debug { - iproduct!(ChunkZ::iter(), ChunkX::iter()).map(|(z, x)| ChunkCoords { x, z }) - } - - /// Iterates over all values stored in the [ChunkArray] - #[inline] - pub fn values(&self) -> impl Iterator + Clone + Debug { - Self::keys().map(|k| &self[k]) - } - - /// Iterates over pairs of chunk coordinate pairs and corresponding stored values - #[inline] - pub fn iter(&self) -> impl Iterator + Clone + Debug { - Self::keys().map(|k| (k, &self[k])) - } -} - -impl Index for ChunkArray { - type Output = T; - - #[inline] - fn index(&self, index: ChunkCoords) -> &Self::Output { - &self.0[index.z.0 as usize][index.x.0 as usize] - } -} - -impl IndexMut for ChunkArray { - #[inline] - fn index_mut(&mut self, index: ChunkCoords) -> &mut Self::Output { - &mut self.0[index.z.0 as usize][index.x.0 as usize] - } -} diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index c725ae2..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,51 +0,0 @@ -# This is an example docker-compose configuration providing a Minecraft server, -# map generator and webserver. Visit http://localhost:8080 to view the map. -# -# See https://docker-minecraft-server.readthedocs.io/ for more information on -# the itzg/minecraft-server image and its configuration. - -services: - mc: - image: docker.io/itzg/minecraft-server - environment: - EULA: 'true' - ports: - - '25565:25565' - volumes: - - data:/data - stdin_open: true - tty: true - restart: unless-stopped - - minedmap: - image: ghcr.io/neocturne/minedmap/minedmap - command: - - '--jobs-initial=2' - - '--image-format=webp' - - '--sign-filter=\[Map\]' - - '--sign-transform=s/\[Map\]//' - - '--watch' - - '/input/world' - - '/output' - volumes: - - data:/input:ro - - output:/output - - processed:/output/processed - network_mode: 'none' - depends_on: - mc: - condition: service_healthy - restart: unless-stopped - - viewer: - image: ghcr.io/neocturne/minedmap/viewer - ports: - - '8080:80' - volumes: - - output:/usr/share/nginx/html/data:ro - restart: unless-stopped - -volumes: - data: {} - processed: {} - output: {} diff --git a/docs/images/signs.png b/docs/images/signs.png deleted file mode 100644 index d1d644d..0000000 Binary files a/docs/images/signs.png and /dev/null differ diff --git a/resource/README.md b/resource/README.md deleted file mode 100644 index 12302ec..0000000 --- a/resource/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# Resource management - -## Scripts - -The following scripts can be found in the `resource` directory of this Git -repository. Python 3.8 should be sufficient, older versions may or may not -work. - -- `blocklist.py`: Lists all supported block IDs of an unpacked Minecraft JAR, or diffs the ID lists - of two different versions -- `extract.py`: Takes the block type information from `blocks.json` and texture data - from an unpacked Minecraft JAR, storing the result in `colors.json` -- `generate.py`: Generates `block_types.rs` from `colors.json` -- `biomes.py`: Generates `biomes.rs` from biome JSON files of an unpacked - Minecraft JAR -- `sign_textures.py`: Generates all needed sign graphics from Minecraft assets - -In addition to these scripts, the JSON processor *jq* is a useful tool to work -with MinedMap's resource metadata. - - -## How to add support for block IDs and biomes of a new Minecraft version - -1. Download the Minecraft version you want to support as well as the previous - version currently supported by MinedMap. You can use the Minecraft launcher - to do so. On Linux the downloaded JAR archive can be found at - `~/.minecraft/versions/`. -2. Unpack both versions to different directories. The next part assumes that - the unpacked data is stored in `resource/data/old` and `resource/data/new`; - using the respective Minecraft version numbers instead of `old` - and `new` is advisable. -3. Check the added and removed block types using `blocklist.py`: - - ```sh - ./blocklist.py diff data/old data/new - ``` - -4. Append all new block types to `blocks.json`. The following command can be - used to generate the basic JSON structure: - - ```sh - ./blocklist.py added data/old data/new | jq -R -n -S --tab '[inputs] | map({key: ., value: {}}) | from_entries' - ``` - -5. Edit `blocks.json` until the following command passes without errors: - - ```sh - ./extract.py blocks.json data/new colors.json - ``` - - If possible, the top texture of blocks should be used where different sides - exist. Block types that should not be visible on the map are just set to - `null` in the JSON (or have a `null` `texture` field when other flags need - to be set, like for sign blocks). - - The `water`, `grass` and `foliage` flags control biome-dependent texture color modifiers. - -6. When `colors.json` builds successfully, use the following command to sort - `blocks.json` by block ID: - - ```sh - jq --tab -S < blocks.json > blocks.json.new && mv blocks.json.new blocks.json - ``` - - Then regenerate `colors.json` one last time, so it is sorted as well. - -7. Update the source code with the new block colors: - - ```sh - ./generate.py colors.json ../crates/resource/src/block_types.rs - cargo fmt --all - ``` - -8. Update the source code for new biome data: - - ```sh - ./biomes.py data/new ../crates/resource/src/biomes.rs - cargo fmt --all - ``` - - After regenerating, check if only new biomes were added. If entries - got removed, biomes may have been renamed or merged, requiring updates - to the alias list in `crates/resource/src/legacy_biomes.rs`. - -After the update, the new version should be tested with old savegames (both -before and after migration by the new version) as well as newly generated -worlds. Use creative mode to add the new block types to your test world. diff --git a/resource/biomes.py b/resource/biomes.py deleted file mode 100755 index 4e3bc51..0000000 --- a/resource/biomes.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python3 - -import json -import os -import sys - - -if len(sys.argv) != 3: - sys.exit('Usage: biomes.py ') - -biomes = {} - -for file in os.scandir(os.path.join(sys.argv[1], 'data/minecraft/worldgen/biome')): - (name, ext) = os.path.splitext(file.name) - if ext != '.json': - continue - with open(file) as f: - data = json.load(f) - biomes[name] = { - 'downfall': data['downfall'], - 'temperature': data['temperature'], - 'foliage_color': data['effects'].get('foliage_color'), - 'grass_color': data['effects'].get('grass_color'), - 'grass_color_modifier': data['effects'].get('grass_color_modifier'), - 'water_color': data['effects'].get('water_color'), - } - -def color(v): - return f'[{v>>16}, {(v>>8)&0xff}, {v&0xff}]' - -# Converts the snake_case grass color modifier to CamelCase -def modify(v): - return ''.join([s.capitalize() for s in v.split('_')]) - -def gen_biome(name, info, f): - temp = round(100*info['temperature']) - downfall = round(100*info['downfall']) - foliage_color = info['foliage_color'] - grass_color = info['grass_color'] - grass_color_modifier = info['grass_color_modifier'] - water_color = info['water_color'] - - print(f'\t("{name}", Biome::new({temp}, {downfall})', file=f) - - if foliage_color is not None: - print(f'\t\t.foliage({color(foliage_color)})', file=f) - if grass_color is not None: - print(f'\t\t.grass({color(grass_color)})', file=f) - if grass_color_modifier is not None: - print(f'\t\t.modify({modify(grass_color_modifier)})', file=f) - if water_color is not None and water_color != 0x3f76e4: - print(f'\t\t.water({color(water_color)})', file=f) - - print('\t),', file=f) - -with open(sys.argv[2], 'w') as f: - print('//! Biome data', file=f); - print('//!', file=f); - print('//! This file is generated using resource/biomes.py, do not edit', file=f); - print('', file=f) - print('use super::*;', file=f) - print('use BiomeGrassColorModifier::*;', file=f) - print('', file=f) - print('/// List if known biomes and their properties', file=f); - print('pub const BIOMES: &[(&str, Biome)] = &[', file=f) - - for name in sorted(biomes): - gen_biome(name, biomes[name], f) - - print('];', file=f) diff --git a/resource/blocklist.py b/resource/blocklist.py deleted file mode 100755 index d3de297..0000000 --- a/resource/blocklist.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import os -import sys - -def blocklist(path): - blockpath = os.path.join(path, 'assets', 'minecraft', 'blockstates') - try: - return map( - lambda filename: filename[:-5], - filter( - lambda filename: filename.endswith('.json'), - os.listdir(blockpath), - ), - ) - except FileNotFoundError: - sys.exit(''' -Path '{}' not found. -Please pass a directory containing the unpacked contents of a JAR of a recent Minecraft version. - '''.strip().format(blockpath)) - -def print_blocklist(path): - for block in sorted(blocklist(path)): - print(block) - -def diff_blocklist(old, new, cmd): - blocks_old = set(blocklist(old)) - blocks_new = set(blocklist(new)) - diff = sorted(blocks_old.symmetric_difference(blocks_new)) - - for block in diff: - if block in blocks_old: - if cmd == 'removed': - print(block) - elif cmd == 'diff': - print('-', block) - else: - if cmd == 'added': - print(block) - elif cmd == 'diff': - print('+', block) - - -parser = argparse.ArgumentParser(description='List block IDs of an unpacked Minecraft JAR, or diff two versions') - -subparsers = parser.add_subparsers(dest='cmd', metavar='COMMAND', required=True) - -parse_list = subparsers.add_parser('list', help='list supported blocks') -parse_list.add_argument('DIR') - -parse_added = subparsers.add_parser('added', help='list added blocks') -parse_added.add_argument('OLD') -parse_added.add_argument('NEW') - -parse_removed = subparsers.add_parser('removed', help='list removed blocks') -parse_removed.add_argument('OLD') -parse_removed.add_argument('NEW') - -parse_removed = subparsers.add_parser('diff', help='diff lists of supported blocks') -parse_removed.add_argument('OLD') -parse_removed.add_argument('NEW') - -args = parser.parse_args() - -if args.cmd == 'list': - print_blocklist(args.DIR) -else: - diff_blocklist(args.OLD, args.NEW, args.cmd) diff --git a/resource/blocks.json b/resource/blocks.json index 15dae2b..e16d69b 100644 --- a/resource/blocks.json +++ b/resource/blocks.json @@ -9,10 +9,6 @@ "acacia_fence_gate": { "texture": "acacia_planks" }, - "acacia_hanging_sign": { - "sign_material": "acacia", - "texture": null - }, "acacia_leaves": { "foliage": true }, @@ -25,8 +21,7 @@ }, "acacia_sapling": {}, "acacia_sign": { - "sign_material": "acacia", - "texture": null + "texture": "acacia_planks" }, "acacia_slab": { "texture": "acacia_planks" @@ -35,24 +30,13 @@ "texture": "acacia_planks" }, "acacia_trapdoor": {}, - "acacia_wall_hanging_sign": { - "sign_material": "acacia", - "texture": null, - "wall_sign": true - }, - "acacia_wall_sign": { - "sign_material": "acacia", - "texture": null, - "wall_sign": true - }, + "acacia_wall_sign": null, "acacia_wood": { "texture": "acacia_log" }, "activator_rail": {}, "air": null, "allium": null, - "amethyst_block": {}, - "amethyst_cluster": {}, "ancient_debris": { "texture": "ancient_debris_top" }, @@ -75,64 +59,11 @@ "attached_pumpkin_stem": { "grass": true }, - "azalea": { - "texture": "azalea_top" - }, - "azalea_leaves": {}, "azure_bluet": null, "bamboo": { "texture": "bamboo_stalk" }, - "bamboo_block": { - "texture": "bamboo_block_top" - }, - "bamboo_button": null, - "bamboo_door": { - "texture": "bamboo_door_top" - }, - "bamboo_fence": { - "texture": "bamboo_planks" - }, - "bamboo_fence_gate": { - "texture": "bamboo_planks" - }, - "bamboo_hanging_sign": { - "sign_material": "bamboo", - "texture": null - }, - "bamboo_mosaic": {}, - "bamboo_mosaic_slab": { - "texture": "bamboo_mosaic" - }, - "bamboo_mosaic_stairs": { - "texture": "bamboo_mosaic" - }, - "bamboo_planks": {}, - "bamboo_pressure_plate": { - "texture": "bamboo_planks" - }, "bamboo_sapling": null, - "bamboo_sign": { - "sign_material": "bamboo", - "texture": null - }, - "bamboo_slab": { - "texture": "bamboo_planks" - }, - "bamboo_stairs": { - "texture": "bamboo_planks" - }, - "bamboo_trapdoor": {}, - "bamboo_wall_hanging_sign": { - "sign_material": "bamboo", - "texture": null, - "wall_sign": true - }, - "bamboo_wall_sign": { - "sign_material": "bamboo", - "texture": null, - "wall_sign": true - }, "barrel": { "texture": "barrel_top" }, @@ -154,10 +85,6 @@ "bell": { "texture": "bell_top" }, - "big_dripleaf": { - "texture": "big_dripleaf_top" - }, - "big_dripleaf_stem": null, "birch_button": null, "birch_door": { "texture": "birch_door_top" @@ -168,10 +95,6 @@ "birch_fence_gate": { "texture": "birch_planks" }, - "birch_hanging_sign": { - "sign_material": "birch", - "texture": null - }, "birch_leaves": { "birch": true }, @@ -184,8 +107,7 @@ }, "birch_sapling": {}, "birch_sign": { - "sign_material": "birch", - "texture": null + "texture": "birch_planks" }, "birch_slab": { "texture": "birch_planks" @@ -194,25 +116,12 @@ "texture": "birch_planks" }, "birch_trapdoor": {}, - "birch_wall_hanging_sign": { - "sign_material": "birch", - "texture": null, - "wall_sign": true - }, - "birch_wall_sign": { - "sign_material": "birch", - "texture": null, - "wall_sign": true - }, + "birch_wall_sign": null, "birch_wood": { "texture": "birch_log" }, "black_banner": null, "black_bed": null, - "black_candle": null, - "black_candle_cake": { - "texture": "cake_top" - }, "black_carpet": { "texture": "black_wool" }, @@ -244,10 +153,6 @@ }, "blue_banner": null, "blue_bed": null, - "blue_candle": null, - "blue_candle_cake": { - "texture": "cake_top" - }, "blue_carpet": { "texture": "blue_wool" }, @@ -287,10 +192,6 @@ "bricks": {}, "brown_banner": null, "brown_bed": null, - "brown_candle": null, - "brown_candle_cake": { - "texture": "cake_top" - }, "brown_carpet": { "texture": "brown_wool" }, @@ -315,28 +216,15 @@ "bubble_coral_block": {}, "bubble_coral_fan": null, "bubble_coral_wall_fan": null, - "budding_amethyst": {}, - "bush": { - "grass": true - }, "cactus": { "texture": "cactus_top" }, - "cactus_flower": {}, "cake": { "texture": "cake_top" }, - "calcite": {}, - "calibrated_sculk_sensor": { - "texture": "calibrated_sculk_sensor_top" - }, "campfire": { "texture": "campfire_log_lit" }, - "candle": null, - "candle_cake": { - "texture": "cake_top" - }, "carrots": { "texture": "carrots_stage3" }, @@ -350,102 +238,32 @@ "texture": "cauldron_top" }, "cave_air": null, - "cave_vines": {}, - "cave_vines_plant": {}, "chain": null, "chain_command_block": { "texture": "chain_command_block_side" }, - "cherry_button": null, - "cherry_door": { - "texture": "cherry_door_top" - }, - "cherry_fence": { - "texture": "cherry_planks" - }, - "cherry_fence_gate": { - "texture": "cherry_planks" - }, - "cherry_hanging_sign": { - "sign_material": "cherry", - "texture": null - }, - "cherry_leaves": {}, - "cherry_log": { - "texture": "cherry_log_top" - }, - "cherry_planks": {}, - "cherry_pressure_plate": { - "texture": "cherry_planks" - }, - "cherry_sapling": null, - "cherry_sign": { - "sign_material": "cherry", - "texture": null - }, - "cherry_slab": { - "texture": "cherry_planks" - }, - "cherry_stairs": { - "texture": "cherry_planks" - }, - "cherry_trapdoor": {}, - "cherry_wall_hanging_sign": { - "sign_material": "cherry", - "texture": null, - "wall_sign": true - }, - "cherry_wall_sign": { - "sign_material": "cherry", - "texture": null, - "wall_sign": true - }, - "cherry_wood": { - "texture": "cherry_log" - }, "chest": { "texture": "oak_planks" }, "chipped_anvil": { "texture": "chipped_anvil_top" }, - "chiseled_bookshelf": { - "texture": "chiseled_bookshelf_top" - }, - "chiseled_copper": {}, - "chiseled_deepslate": {}, "chiseled_nether_bricks": {}, "chiseled_polished_blackstone": {}, "chiseled_quartz_block": {}, "chiseled_red_sandstone": { "texture": "red_sandstone_top" }, - "chiseled_resin_bricks": {}, "chiseled_sandstone": { "texture": "sandstone_top" }, "chiseled_stone_bricks": {}, - "chiseled_tuff": {}, - "chiseled_tuff_bricks": { - "texture": "chiseled_tuff_bricks_top" - }, "chorus_flower": {}, "chorus_plant": {}, "clay": {}, - "closed_eyeblossom": null, "coal_block": {}, "coal_ore": {}, "coarse_dirt": {}, - "cobbled_deepslate": {}, - "cobbled_deepslate_slab": { - "texture": "cobbled_deepslate" - }, - "cobbled_deepslate_stairs": { - "texture": "cobbled_deepslate" - }, - "cobbled_deepslate_wall": { - "texture": "cobbled_deepslate" - }, "cobblestone": {}, "cobblestone_slab": { "texture": "cobblestone" @@ -468,29 +286,13 @@ "texture": "composter_compost" }, "conduit": {}, - "copper_block": {}, - "copper_bulb": {}, - "copper_door": { - "texture": "copper_door_top" - }, - "copper_grate": {}, - "copper_ore": {}, - "copper_trapdoor": {}, "cornflower": null, - "cracked_deepslate_bricks": {}, - "cracked_deepslate_tiles": {}, "cracked_nether_bricks": {}, "cracked_polished_blackstone_bricks": {}, "cracked_stone_bricks": {}, - "crafter": { - "texture": "crafter_top" - }, "crafting_table": { "texture": "crafting_table_top" }, - "creaking_heart": { - "texture": "creaking_heart_top" - }, "creeper_head": null, "creeper_wall_head": null, "crimson_button": null, @@ -504,10 +306,6 @@ "texture": "crimson_planks" }, "crimson_fungus": null, - "crimson_hanging_sign": { - "sign_material": "crimson", - "texture": null - }, "crimson_hyphae": { "texture": "crimson_stem" }, @@ -518,8 +316,7 @@ }, "crimson_roots": {}, "crimson_sign": { - "sign_material": "crimson", - "texture": null + "texture": "crimson_planks" }, "crimson_slab": { "texture": "crimson_planks" @@ -531,24 +328,8 @@ "texture": "crimson_stem_top" }, "crimson_trapdoor": {}, - "crimson_wall_hanging_sign": { - "sign_material": "crimson", - "texture": null, - "wall_sign": true - }, - "crimson_wall_sign": { - "sign_material": "crimson", - "texture": null, - "wall_sign": true - }, + "crimson_wall_sign": null, "crying_obsidian": {}, - "cut_copper": {}, - "cut_copper_slab": { - "texture": "cut_copper" - }, - "cut_copper_stairs": { - "texture": "cut_copper" - }, "cut_red_sandstone": { "texture": "red_sandstone_top" }, @@ -563,10 +344,6 @@ }, "cyan_banner": null, "cyan_bed": null, - "cyan_candle": null, - "cyan_candle_cake": { - "texture": "cake_top" - }, "cyan_carpet": { "texture": "cyan_wool" }, @@ -595,10 +372,6 @@ "dark_oak_fence_gate": { "texture": "dark_oak_planks" }, - "dark_oak_hanging_sign": { - "sign_material": "dark_oak", - "texture": null - }, "dark_oak_leaves": { "foliage": true }, @@ -611,8 +384,7 @@ }, "dark_oak_sapling": {}, "dark_oak_sign": { - "sign_material": "dark_oak", - "texture": null + "texture": "dark_oak_planks" }, "dark_oak_slab": { "texture": "dark_oak_planks" @@ -621,16 +393,7 @@ "texture": "dark_oak_planks" }, "dark_oak_trapdoor": {}, - "dark_oak_wall_hanging_sign": { - "sign_material": "dark_oak", - "texture": null, - "wall_sign": true - }, - "dark_oak_wall_sign": { - "sign_material": "dark_oak", - "texture": null, - "wall_sign": true - }, + "dark_oak_wall_sign": null, "dark_oak_wood": { "texture": "dark_oak_log" }, @@ -665,38 +428,6 @@ "dead_tube_coral_block": {}, "dead_tube_coral_fan": null, "dead_tube_coral_wall_fan": null, - "decorated_pot": { - "texture": "flower_pot" - }, - "deepslate": {}, - "deepslate_brick_slab": { - "texture": "deepslate_bricks" - }, - "deepslate_brick_stairs": { - "texture": "deepslate_bricks" - }, - "deepslate_brick_wall": { - "texture": "deepslate_bricks" - }, - "deepslate_bricks": {}, - "deepslate_coal_ore": {}, - "deepslate_copper_ore": {}, - "deepslate_diamond_ore": {}, - "deepslate_emerald_ore": {}, - "deepslate_gold_ore": {}, - "deepslate_iron_ore": {}, - "deepslate_lapis_ore": {}, - "deepslate_redstone_ore": {}, - "deepslate_tile_slab": { - "texture": "deepslate_tiles" - }, - "deepslate_tile_stairs": { - "texture": "deepslate_tiles" - }, - "deepslate_tile_wall": { - "texture": "deepslate_tiles" - }, - "deepslate_tiles": {}, "detector_rail": {}, "diamond_block": {}, "diamond_ore": {}, @@ -711,22 +442,15 @@ "texture": "diorite" }, "dirt": {}, - "dirt_path": { - "texture": "dirt_path_top" - }, "dispenser": { "texture": "furnace_top" }, "dragon_egg": {}, "dragon_head": null, "dragon_wall_head": null, - "dried_ghast": { - "texture": "dried_ghast_hydration_1_top" - }, "dried_kelp_block": { "texture": "dried_kelp_top" }, - "dripstone_block": {}, "dropper": { "texture": "furnace_top" }, @@ -759,21 +483,6 @@ "ender_chest": { "texture": "obsidian" }, - "exposed_chiseled_copper": {}, - "exposed_copper": {}, - "exposed_copper_bulb": {}, - "exposed_copper_door": { - "texture": "exposed_copper_door_top" - }, - "exposed_copper_grate": {}, - "exposed_copper_trapdoor": {}, - "exposed_cut_copper": {}, - "exposed_cut_copper_slab": { - "texture": "exposed_cut_copper" - }, - "exposed_cut_copper_stairs": { - "texture": "exposed_cut_copper" - }, "farmland": { "texture": "farmland_moist" }, @@ -785,16 +494,10 @@ "fire_coral_block": {}, "fire_coral_fan": null, "fire_coral_wall_fan": null, - "firefly_bush": {}, "fletching_table": { "texture": "fletching_table_top" }, "flower_pot": {}, - "flowering_azalea": { - "texture": "flowering_azalea_top" - }, - "flowering_azalea_leaves": {}, - "frogspawn": {}, "frosted_ice": { "texture": "frosted_ice_0" }, @@ -806,8 +509,6 @@ "glass_pane": { "texture": "glass_pane_top" }, - "glow_item_frame": null, - "glow_lichen": null, "glowstone": {}, "gold_block": {}, "gold_ore": {}, @@ -827,15 +528,11 @@ "texture": "grass_block_top" }, "grass_path": { - "texture": "dirt_path_top" + "texture": "grass_path_top" }, "gravel": {}, "gray_banner": null, "gray_bed": null, - "gray_candle": null, - "gray_candle_cake": { - "texture": "cake_top" - }, "gray_carpet": { "texture": "gray_wool" }, @@ -852,10 +549,6 @@ "gray_wool": {}, "green_banner": null, "green_bed": null, - "green_candle": null, - "green_candle_cake": { - "texture": "cake_top" - }, "green_carpet": { "texture": "green_wool" }, @@ -873,11 +566,9 @@ "grindstone": { "texture": "grindstone_round" }, - "hanging_roots": {}, "hay_block": { "texture": "hay_block_top" }, - "heavy_core": {}, "heavy_weighted_pressure_plate": { "texture": "iron_block" }, @@ -902,9 +593,6 @@ "infested_cracked_stone_bricks": { "texture": "cracked_stone_bricks" }, - "infested_deepslate": { - "texture": "deepslate" - }, "infested_mossy_stone_bricks": { "texture": "mossy_stone_bricks" }, @@ -939,10 +627,6 @@ "jungle_fence_gate": { "texture": "jungle_planks" }, - "jungle_hanging_sign": { - "sign_material": "jungle", - "texture": null - }, "jungle_leaves": { "foliage": true }, @@ -955,8 +639,7 @@ }, "jungle_sapling": {}, "jungle_sign": { - "sign_material": "jungle", - "texture": null + "texture": "jungle_planks" }, "jungle_slab": { "texture": "jungle_planks" @@ -965,16 +648,7 @@ "texture": "jungle_planks" }, "jungle_trapdoor": {}, - "jungle_wall_hanging_sign": { - "sign_material": "jungle", - "texture": null, - "wall_sign": true - }, - "jungle_wall_sign": { - "sign_material": "jungle", - "texture": null, - "wall_sign": true - }, + "jungle_wall_sign": null, "jungle_wood": { "texture": "jungle_log" }, @@ -984,7 +658,6 @@ "lantern": {}, "lapis_block": {}, "lapis_ore": {}, - "large_amethyst_bud": null, "large_fern": { "grass": true, "texture": "large_fern_top" @@ -992,21 +665,12 @@ "lava": { "texture": "lava_still" }, - "lava_cauldron": { - "texture": "cauldron_top" - }, - "leaf_litter": null, "lectern": { "texture": "lectern_top" }, "lever": null, - "light": null, "light_blue_banner": null, "light_blue_bed": null, - "light_blue_candle": null, - "light_blue_candle_cake": { - "texture": "cake_top" - }, "light_blue_carpet": { "texture": "light_blue_wool" }, @@ -1023,10 +687,6 @@ "light_blue_wool": {}, "light_gray_banner": null, "light_gray_bed": null, - "light_gray_candle": null, - "light_gray_candle_cake": { - "texture": "cake_top" - }, "light_gray_carpet": { "texture": "light_gray_wool" }, @@ -1044,7 +704,6 @@ "light_weighted_pressure_plate": { "texture": "gold_block" }, - "lightning_rod": null, "lilac": { "texture": "lilac_top" }, @@ -1054,10 +713,6 @@ }, "lime_banner": null, "lime_bed": null, - "lime_candle": null, - "lime_candle_cake": { - "texture": "cake_top" - }, "lime_carpet": { "texture": "lime_wool" }, @@ -1080,10 +735,6 @@ }, "magenta_banner": null, "magenta_bed": null, - "magenta_candle": null, - "magenta_candle_cake": { - "texture": "cake_top" - }, "magenta_carpet": { "texture": "magenta_wool" }, @@ -1101,69 +752,12 @@ "magma_block": { "texture": "magma" }, - "mangrove_button": null, - "mangrove_door": { - "texture": "mangrove_door_top" - }, - "mangrove_fence": { - "texture": "mangrove_planks" - }, - "mangrove_fence_gate": { - "texture": "mangrove_planks" - }, - "mangrove_hanging_sign": { - "sign_material": "mangrove", - "texture": null - }, - "mangrove_leaves": { - "foliage": true - }, - "mangrove_log": { - "texture": "mangrove_log_top" - }, - "mangrove_planks": {}, - "mangrove_pressure_plate": { - "texture": "mangrove_planks" - }, - "mangrove_propagule": {}, - "mangrove_roots": { - "texture": "mangrove_roots_top" - }, - "mangrove_sign": { - "sign_material": "mangrove", - "texture": null - }, - "mangrove_slab": { - "texture": "mangrove_planks" - }, - "mangrove_stairs": { - "texture": "mangrove_planks" - }, - "mangrove_trapdoor": {}, - "mangrove_wall_hanging_sign": { - "sign_material": "mangrove", - "texture": null, - "wall_sign": true - }, - "mangrove_wall_sign": { - "sign_material": "mangrove", - "texture": null, - "wall_sign": true - }, - "mangrove_wood": { - "texture": "mangrove_log" - }, - "medium_amethyst_bud": null, "melon": { "texture": "melon_top" }, "melon_stem": { "grass": true }, - "moss_block": {}, - "moss_carpet": { - "texture": "moss_block" - }, "mossy_cobblestone": {}, "mossy_cobblestone_slab": { "texture": "mossy_cobblestone" @@ -1185,20 +779,6 @@ }, "mossy_stone_bricks": {}, "moving_piston": null, - "mud": {}, - "mud_brick_slab": { - "texture": "mud_bricks" - }, - "mud_brick_stairs": { - "texture": "mud_bricks" - }, - "mud_brick_wall": { - "texture": "mud_bricks" - }, - "mud_bricks": {}, - "muddy_mangrove_roots": { - "texture": "muddy_mangrove_roots_top" - }, "mushroom_stem": {}, "mycelium": { "texture": "mycelium_top" @@ -1237,10 +817,6 @@ "oak_fence_gate": { "texture": "oak_planks" }, - "oak_hanging_sign": { - "sign_material": "oak", - "texture": null - }, "oak_leaves": { "foliage": true }, @@ -1253,8 +829,7 @@ }, "oak_sapling": {}, "oak_sign": { - "sign_material": "oak", - "texture": null + "texture": "oak_planks" }, "oak_slab": { "texture": "oak_planks" @@ -1263,16 +838,7 @@ "texture": "oak_planks" }, "oak_trapdoor": {}, - "oak_wall_hanging_sign": { - "sign_material": "oak", - "texture": null, - "wall_sign": true - }, - "oak_wall_sign": { - "sign_material": "oak", - "texture": null, - "wall_sign": true - }, + "oak_wall_sign": null, "oak_wood": { "texture": "oak_log" }, @@ -1280,16 +846,8 @@ "texture": "observer_top" }, "obsidian": {}, - "ochre_froglight": { - "texture": "ochre_froglight_top" - }, - "open_eyeblossom": null, "orange_banner": null, "orange_bed": null, - "orange_candle": null, - "orange_candle_cake": { - "texture": "cake_top" - }, "orange_carpet": { "texture": "orange_wool" }, @@ -1306,97 +864,21 @@ "orange_wall_banner": null, "orange_wool": {}, "oxeye_daisy": null, - "oxidized_chiseled_copper": {}, - "oxidized_copper": {}, - "oxidized_copper_bulb": {}, - "oxidized_copper_door": { - "texture": "oxidized_copper_door_top" - }, - "oxidized_copper_grate": {}, - "oxidized_copper_trapdoor": {}, - "oxidized_cut_copper": {}, - "oxidized_cut_copper_slab": { - "texture": "oxidized_cut_copper" - }, - "oxidized_cut_copper_stairs": { - "texture": "oxidized_cut_copper" - }, "packed_ice": {}, - "packed_mud": {}, - "pale_hanging_moss": null, - "pale_moss_block": {}, - "pale_moss_carpet": {}, - "pale_oak_button": null, - "pale_oak_door": { - "texture": "pale_oak_door_top" - }, - "pale_oak_fence": { - "texture": "pale_oak_planks" - }, - "pale_oak_fence_gate": { - "texture": "pale_oak_planks" - }, - "pale_oak_hanging_sign": { - "sign_material": "pale_oak", - "texture": null - }, - "pale_oak_leaves": {}, - "pale_oak_log": { - "texture": "pale_oak_log_top" - }, - "pale_oak_planks": {}, - "pale_oak_pressure_plate": { - "texture": "pale_oak_planks" - }, - "pale_oak_sapling": {}, - "pale_oak_sign": { - "sign_material": "pale_oak", - "texture": null - }, - "pale_oak_slab": { - "texture": "pale_oak_planks" - }, - "pale_oak_stairs": { - "texture": "pale_oak_planks" - }, - "pale_oak_trapdoor": {}, - "pale_oak_wall_hanging_sign": { - "sign_material": "pale_oak", - "texture": null, - "wall_sign": true - }, - "pale_oak_wall_sign": { - "sign_material": "pale_oak", - "texture": null, - "wall_sign": true - }, - "pale_oak_wood": { - "texture": "pale_oak_log" - }, - "pearlescent_froglight": { - "texture": "pearlescent_froglight_top" - }, "peony": { "texture": "peony_top" }, "petrified_oak_slab": { "texture": "oak_planks" }, - "piglin_head": null, - "piglin_wall_head": null, "pink_banner": null, "pink_bed": null, - "pink_candle": null, - "pink_candle_cake": { - "texture": "cake_top" - }, "pink_carpet": { "texture": "pink_wool" }, "pink_concrete": {}, "pink_concrete_powder": {}, "pink_glazed_terracotta": {}, - "pink_petals": null, "pink_shulker_box": {}, "pink_stained_glass": {}, "pink_stained_glass_pane": { @@ -1412,20 +894,11 @@ "piston_head": { "texture": "piston_top" }, - "pitcher_crop": { - "texture": "pitcher_crop_top" - }, - "pitcher_plant": { - "texture": "pitcher_crop_top_stage_4" - }, "player_head": null, "player_wall_head": null, "podzol": { "texture": "podzol_top" }, - "pointed_dripstone": { - "texture": "pointed_dripstone_down_base" - }, "polished_andesite": {}, "polished_andesite_slab": { "texture": "polished_andesite" @@ -1460,16 +933,6 @@ "polished_blackstone_wall": { "texture": "polished_blackstone" }, - "polished_deepslate": {}, - "polished_deepslate_slab": { - "texture": "polished_deepslate" - }, - "polished_deepslate_stairs": { - "texture": "polished_deepslate" - }, - "polished_deepslate_wall": { - "texture": "polished_deepslate" - }, "polished_diorite": {}, "polished_diorite_slab": { "texture": "polished_diorite" @@ -1484,16 +947,6 @@ "polished_granite_stairs": { "texture": "polished_granite" }, - "polished_tuff": {}, - "polished_tuff_slab": { - "texture": "polished_tuff" - }, - "polished_tuff_stairs": { - "texture": "polished_tuff" - }, - "polished_tuff_wall": { - "texture": "polished_tuff" - }, "poppy": null, "potatoes": { "texture": "potatoes_stage3" @@ -1504,9 +957,6 @@ "potted_allium": { "texture": "allium" }, - "potted_azalea_bush": { - "texture": "azalea_top" - }, "potted_azure_bluet": { "texture": "azure_bluet" }, @@ -1525,12 +975,6 @@ "potted_cactus": { "texture": "cactus_top" }, - "potted_cherry_sapling": { - "texture": "cherry_sapling" - }, - "potted_closed_eyeblossom": { - "texture": "closed_eyeblossom" - }, "potted_cornflower": { "texture": "cornflower" }, @@ -1553,33 +997,21 @@ "grass": true, "texture": "fern" }, - "potted_flowering_azalea_bush": { - "texture": "flowering_azalea_top" - }, "potted_jungle_sapling": { "texture": "jungle_sapling" }, "potted_lily_of_the_valley": { "texture": "lily_of_the_valley" }, - "potted_mangrove_propagule": { - "texture": "mangrove_propagule" - }, "potted_oak_sapling": { "texture": "oak_sapling" }, - "potted_open_eyeblossom": { - "texture": "open_eyeblossom" - }, "potted_orange_tulip": { "texture": "orange_tulip" }, "potted_oxeye_daisy": { "texture": "oxeye_daisy" }, - "potted_pale_oak_sapling": { - "texture": "pale_oak_sapling" - }, "potted_pink_tulip": { "texture": "pink_tulip" }, @@ -1595,9 +1027,6 @@ "potted_spruce_sapling": { "texture": "spruce_sapling" }, - "potted_torchflower": { - "texture": "torchflower" - }, "potted_warped_fungus": { "texture": "warped_fungus" }, @@ -1610,10 +1039,6 @@ "potted_wither_rose": { "texture": "wither_rose" }, - "powder_snow": {}, - "powder_snow_cauldron": { - "texture": "cauldron_top" - }, "powered_rail": {}, "prismarine": {}, "prismarine_brick_slab": { @@ -1640,10 +1065,6 @@ }, "purple_banner": null, "purple_bed": null, - "purple_candle": null, - "purple_candle_cake": { - "texture": "cake_top" - }, "purple_carpet": { "texture": "purple_wool" }, @@ -1678,15 +1099,8 @@ "texture": "quartz_block_top" }, "rail": {}, - "raw_copper_block": {}, - "raw_gold_block": {}, - "raw_iron_block": {}, "red_banner": null, "red_bed": null, - "red_candle": null, - "red_candle_cake": { - "texture": "cake_top" - }, "red_carpet": { "texture": "red_wool" }, @@ -1735,29 +1149,13 @@ "redstone_wire": { "texture": "redstone_block" }, - "reinforced_deepslate": { - "texture": "reinforced_deepslate_top" - }, "repeater": {}, "repeating_command_block": { "texture": "repeating_command_block_front" }, - "resin_block": {}, - "resin_brick_slab": { - "texture": "resin_bricks" - }, - "resin_brick_stairs": { - "texture": "resin_bricks" - }, - "resin_brick_wall": { - "texture": "resin_bricks" - }, - "resin_bricks": {}, - "resin_clump": null, "respawn_anchor": { "texture": "respawn_anchor_top" }, - "rooted_dirt": {}, "rose_bush": { "texture": "rose_bush_top" }, @@ -1777,40 +1175,23 @@ "scaffolding": { "texture": "scaffolding_top" }, - "sculk": {}, - "sculk_catalyst": { - "texture": "sculk_catalyst_top" - }, - "sculk_sensor": { - "texture": "sculk_sensor_top" - }, - "sculk_shrieker": { - "texture": "sculk_shrieker_top" - }, - "sculk_vein": {}, "sea_lantern": {}, "sea_pickle": {}, - "seagrass": {}, - "short_dry_grass": {}, - "short_grass": null, + "seagrass": null, "shroomlight": {}, "shulker_box": {}, "sign": { - "sign_material": "oak", - "texture": null + "texture": "oak_planks" }, "skeleton_skull": null, "skeleton_wall_skull": null, "slime_block": {}, - "small_amethyst_bud": null, - "small_dripleaf": null, "smithing_table": { "texture": "smithing_table_top" }, "smoker": { "texture": "smoker_top" }, - "smooth_basalt": {}, "smooth_quartz": { "texture": "quartz_block_top" }, @@ -1842,9 +1223,6 @@ "smooth_stone_slab": { "texture": "smooth_stone" }, - "sniffer_egg": { - "texture": "sniffer_egg_not_cracked_top" - }, "snow": {}, "snow_block": { "texture": "snow" @@ -1862,7 +1240,6 @@ "soul_wall_torch": null, "spawner": {}, "sponge": {}, - "spore_blossom": {}, "spruce_button": null, "spruce_door": { "texture": "spruce_door_top" @@ -1873,10 +1250,6 @@ "spruce_fence_gate": { "texture": "spruce_planks" }, - "spruce_hanging_sign": { - "sign_material": "spruce", - "texture": null - }, "spruce_leaves": { "spruce": true }, @@ -1889,8 +1262,7 @@ }, "spruce_sapling": {}, "spruce_sign": { - "sign_material": "spruce", - "texture": null + "texture": "spruce_planks" }, "spruce_slab": { "texture": "spruce_planks" @@ -1899,16 +1271,7 @@ "texture": "spruce_planks" }, "spruce_trapdoor": {}, - "spruce_wall_hanging_sign": { - "sign_material": "spruce", - "texture": null, - "wall_sign": true - }, - "spruce_wall_sign": { - "sign_material": "spruce", - "texture": null, - "wall_sign": true - }, + "spruce_wall_sign": null, "spruce_wood": { "texture": "spruce_log" }, @@ -1945,21 +1308,12 @@ "stripped_acacia_wood": { "texture": "stripped_acacia_log" }, - "stripped_bamboo_block": { - "texture": "stripped_bamboo_block_top" - }, "stripped_birch_log": { "texture": "stripped_birch_log_top" }, "stripped_birch_wood": { "texture": "stripped_birch_log" }, - "stripped_cherry_log": { - "texture": "stripped_cherry_log_top" - }, - "stripped_cherry_wood": { - "texture": "stripped_cherry_log" - }, "stripped_crimson_hyphae": { "texture": "stripped_crimson_stem" }, @@ -1978,24 +1332,12 @@ "stripped_jungle_wood": { "texture": "stripped_jungle_log" }, - "stripped_mangrove_log": { - "texture": "stripped_mangrove_log_top" - }, - "stripped_mangrove_wood": { - "texture": "stripped_mangrove_log" - }, "stripped_oak_log": { "texture": "stripped_oak_log_top" }, "stripped_oak_wood": { "texture": "stripped_oak_log" }, - "stripped_pale_oak_log": { - "texture": "stripped_pale_oak_log_top" - }, - "stripped_pale_oak_wood": { - "texture": "stripped_pale_oak_log" - }, "stripped_spruce_log": { "texture": "stripped_spruce_log_top" }, @@ -2014,16 +1356,9 @@ "sunflower": { "texture": "sunflower_front" }, - "suspicious_gravel": { - "texture": "suspicious_gravel_0" - }, - "suspicious_sand": { - "texture": "suspicious_sand_0" - }, "sweet_berry_bush": { "texture": "sweet_berry_bush_stage3" }, - "tall_dry_grass": {}, "tall_grass": { "grass": true, "texture": "tall_grass_top" @@ -2035,65 +1370,27 @@ "texture": "target_top" }, "terracotta": {}, - "test_block": null, - "test_instance_block": null, - "tinted_glass": {}, "tnt": { "texture": "tnt_top" }, "torch": null, - "torchflower": null, - "torchflower_crop": null, "trapped_chest": { "texture": "oak_planks" }, - "trial_spawner": { - "texture": "trial_spawner_top_inactive" - }, "tripwire": null, "tripwire_hook": null, "tube_coral": null, "tube_coral_block": {}, "tube_coral_fan": null, "tube_coral_wall_fan": null, - "tuff": {}, - "tuff_brick_slab": { - "texture": "tuff_bricks" - }, - "tuff_brick_stairs": { - "texture": "tuff_bricks" - }, - "tuff_brick_wall": { - "texture": "tuff_bricks" - }, - "tuff_bricks": {}, - "tuff_slab": { - "texture": "tuff" - }, - "tuff_stairs": { - "texture": "tuff" - }, - "tuff_wall": { - "texture": "tuff" - }, "turtle_egg": {}, "twisting_vines": {}, "twisting_vines_plant": {}, - "vault": { - "texture": "vault_top" - }, - "verdant_froglight": { - "texture": "verdant_froglight_top" - }, "vine": { "grass": true }, "void_air": null, - "wall_sign": { - "sign_material": "oak", - "texture": null, - "wall_sign": true - }, + "wall_sign": null, "wall_torch": null, "warped_button": null, "warped_door": { @@ -2106,10 +1403,6 @@ "texture": "warped_planks" }, "warped_fungus": null, - "warped_hanging_sign": { - "sign_material": "warped", - "texture": null - }, "warped_hyphae": { "texture": "warped_stem" }, @@ -2120,8 +1413,7 @@ }, "warped_roots": {}, "warped_sign": { - "sign_material": "warped", - "texture": null + "texture": "warped_planks" }, "warped_slab": { "texture": "warped_planks" @@ -2133,147 +1425,12 @@ "texture": "warped_stem_top" }, "warped_trapdoor": {}, - "warped_wall_hanging_sign": { - "sign_material": "warped", - "texture": null, - "wall_sign": true - }, - "warped_wall_sign": { - "sign_material": "warped", - "texture": null, - "wall_sign": true - }, + "warped_wall_sign": null, "warped_wart_block": {}, "water": { "texture": "water_still", "water": true }, - "water_cauldron": { - "texture": "cauldron_top" - }, - "waxed_chiseled_copper": { - "texture": "chiseled_copper" - }, - "waxed_copper_block": { - "texture": "copper_block" - }, - "waxed_copper_bulb": { - "texture": "copper_bulb" - }, - "waxed_copper_door": { - "texture": "copper_door_top" - }, - "waxed_copper_grate": { - "texture": "copper_grate" - }, - "waxed_copper_trapdoor": { - "texture": "copper_trapdoor" - }, - "waxed_cut_copper": { - "texture": "cut_copper" - }, - "waxed_cut_copper_slab": { - "texture": "cut_copper" - }, - "waxed_cut_copper_stairs": { - "texture": "cut_copper" - }, - "waxed_exposed_chiseled_copper": { - "texture": "exposed_chiseled_copper" - }, - "waxed_exposed_copper": { - "texture": "exposed_copper" - }, - "waxed_exposed_copper_bulb": { - "texture": "exposed_copper_bulb" - }, - "waxed_exposed_copper_door": { - "texture": "exposed_copper_door_top" - }, - "waxed_exposed_copper_grate": { - "texture": "exposed_copper_grate" - }, - "waxed_exposed_copper_trapdoor": { - "texture": "exposed_copper_trapdoor" - }, - "waxed_exposed_cut_copper": { - "texture": "exposed_cut_copper" - }, - "waxed_exposed_cut_copper_slab": { - "texture": "exposed_cut_copper" - }, - "waxed_exposed_cut_copper_stairs": { - "texture": "exposed_cut_copper" - }, - "waxed_oxidized_chiseled_copper": { - "texture": "oxidized_chiseled_copper" - }, - "waxed_oxidized_copper": { - "texture": "oxidized_copper" - }, - "waxed_oxidized_copper_bulb": { - "texture": "oxidized_copper_bulb" - }, - "waxed_oxidized_copper_door": { - "texture": "oxidized_copper_door_top" - }, - "waxed_oxidized_copper_grate": { - "texture": "oxidized_copper_grate" - }, - "waxed_oxidized_copper_trapdoor": { - "texture": "oxidized_copper_trapdoor" - }, - "waxed_oxidized_cut_copper": { - "texture": "oxidized_cut_copper" - }, - "waxed_oxidized_cut_copper_slab": { - "texture": "oxidized_cut_copper" - }, - "waxed_oxidized_cut_copper_stairs": { - "texture": "oxidized_cut_copper" - }, - "waxed_weathered_chiseled_copper": { - "texture": "weathered_chiseled_copper" - }, - "waxed_weathered_copper": { - "texture": "weathered_copper" - }, - "waxed_weathered_copper_bulb": { - "texture": "weathered_copper_bulb" - }, - "waxed_weathered_copper_door": { - "texture": "weathered_copper_door_top" - }, - "waxed_weathered_copper_grate": { - "texture": "weathered_copper_grate" - }, - "waxed_weathered_copper_trapdoor": { - "texture": "weathered_copper_trapdoor" - }, - "waxed_weathered_cut_copper": { - "texture": "weathered_cut_copper" - }, - "waxed_weathered_cut_copper_slab": { - "texture": "weathered_cut_copper" - }, - "waxed_weathered_cut_copper_stairs": { - "texture": "weathered_cut_copper" - }, - "weathered_chiseled_copper": {}, - "weathered_copper": {}, - "weathered_copper_bulb": {}, - "weathered_copper_door": { - "texture": "weathered_copper_door_top" - }, - "weathered_copper_grate": {}, - "weathered_copper_trapdoor": {}, - "weathered_cut_copper": {}, - "weathered_cut_copper_slab": { - "texture": "weathered_cut_copper" - }, - "weathered_cut_copper_stairs": { - "texture": "weathered_cut_copper" - }, "weeping_vines": {}, "weeping_vines_plant": {}, "wet_sponge": {}, @@ -2282,10 +1439,6 @@ }, "white_banner": null, "white_bed": null, - "white_candle": null, - "white_candle_cake": { - "texture": "cake_top" - }, "white_carpet": { "texture": "white_wool" }, @@ -2301,16 +1454,11 @@ "white_tulip": null, "white_wall_banner": null, "white_wool": {}, - "wildflowers": null, "wither_rose": null, "wither_skeleton_skull": null, "wither_skeleton_wall_skull": null, "yellow_banner": null, "yellow_bed": null, - "yellow_candle": null, - "yellow_candle_cake": { - "texture": "cake_top" - }, "yellow_carpet": { "texture": "yellow_wool" }, diff --git a/resource/extract.py b/resource/extract.py index 31c1e97..4e992c2 100755 --- a/resource/extract.py +++ b/resource/extract.py @@ -11,7 +11,7 @@ if len(sys.argv) != 4: sys.exit('Usage: extract.py ') def mean_color(texture): - path = os.path.join(sys.argv[2], 'assets/minecraft/textures/block', texture + '.png') + path = os.path.join(sys.argv[2], texture + '.png') im = Image.open(path) data = im.convert('RGBA').getdata() @@ -35,7 +35,7 @@ with open(sys.argv[1]) as f: output = {} for name, info in blocks.items(): - id = name + id = 'minecraft:' + name output[id] = { 'color': {'r': 0, 'g': 0, 'b': 0}, @@ -45,30 +45,20 @@ for name, info in blocks.items(): 'birch': False, 'spruce': False, 'water': False, - 'wall_sign': False, - 'sign_material': None, } if info is None: continue - texture = info.get('texture', name) - - color = None - if texture: - color = mean_color(texture) + color = mean_color(info.get('texture', name)) if color: output[id]['color'] = color output[id]['opaque'] = True - - output[id]['grass'] = info.get('grass', False) - output[id]['foliage'] = info.get('foliage', False) - output[id]['birch'] = info.get('birch', False) - output[id]['spruce'] = info.get('spruce', False) - output[id]['water'] = info.get('water', False) - output[id]['wall_sign'] = info.get('wall_sign', False) - - output[id]['sign_material'] = info.get('sign_material') + output[id]['grass'] = info.get('grass', False) + output[id]['foliage'] = info.get('foliage', False) + output[id]['birch'] = info.get('birch', False) + output[id]['spruce'] = info.get('spruce', False) + output[id]['water'] = info.get('water', False) with open(sys.argv[3], 'w') as f: json.dump(output, f) diff --git a/resource/generate.py b/resource/generate.py index ab91324..8508c6b 100755 --- a/resource/generate.py +++ b/resource/generate.py @@ -6,7 +6,7 @@ import sys if len(sys.argv) != 3: - sys.exit('Usage: generate.py ') + sys.exit('Usage: extract.py ') with open(sys.argv[1]) as f: colors = json.load(f) @@ -14,47 +14,29 @@ with open(sys.argv[1]) as f: output = {} with open(sys.argv[2], 'w') as f: - print('//! Block type information', file=f); - print('//!', file=f); - print('//! This file is generated using resource/generate.py, do not edit', file=f); - print('', file=f) - print('use enumflags2::make_bitflags;', file=f); - print('', file=f) - print('use super::*;', file=f) - print('', file=f) - print('/// List if known block types and their properties', file=f); - print('pub const BLOCK_TYPES: &[(&str, ConstBlockType)] = &[', file=f) - for name, info in colors.items(): flags = [] if info['opaque']: - flags.append('Opaque') + flags.append('BLOCK_OPAQUE') if info['grass']: - flags.append('Grass') + flags.append('BLOCK_GRASS') if info['foliage']: - flags.append('Foliage') + flags.append('BLOCK_FOLIAGE') if info['birch']: - flags.append('Birch') + flags.append('BLOCK_BIRCH') if info['spruce']: - flags.append('Spruce') + flags.append('BLOCK_SPRUCE') if info['water']: - flags.append('Water') - if info['wall_sign']: - flags.append('WallSign') - flags = 'make_bitflags!(BlockFlag::{' + '|'.join(flags) + '})' + flags.append('BLOCK_WATER') + if flags: + flags = '|'.join(flags) + else: + flags = '0' - sign_material = 'None' - if info['sign_material']: - sign_material = 'Some("%s")' % info['sign_material'] - - print('\t("%s", ConstBlockType { ' % name, file=f) - print('\t\tblock_color: BlockColor { flags: %s, color: Color([%u, %u, %u]) },' % ( + print('{"%s", {%s, {%u, %u, %u}}},' % ( + name, flags, info['color']['r'], info['color']['g'], info['color']['b'], ), file=f) - print('\t\tsign_material: %s,' % sign_material, file=f) - print('}),', file=f) - - print('];', file=f) diff --git a/resource/sign_textures.py b/resource/sign_textures.py deleted file mode 100755 index 846ab3e..0000000 --- a/resource/sign_textures.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python3 - -import shutil -import sys - -from PIL import Image - -MATERIALS = [ - 'acacia', - 'bamboo', - 'birch', - 'cherry', - 'crimson', - 'dark_oak', - 'jungle', - 'mangrove', - 'oak', - 'pale_oak', - 'spruce', - 'warped', -] - -in_dir = sys.argv[1] -out_dir = sys.argv[2] - -def sign_bg_image(material): - in_path = f'{in_dir}/assets/minecraft/textures/entity/signs/{material}.png' - out_path = f'{out_dir}/bg/{material}_sign.png' - out_path_wall = f'{out_dir}/bg/{material}_wall_sign.png' - - in_image = Image.open(in_path) - - out_image = Image.new('RGBA', (24, 26)) - out_image.paste(in_image.crop((2, 2, 26, 14)), (0, 0)) - out_image.paste(in_image.crop((2, 16, 4, 30)), (11, 12)) - out_image.save(out_path) - - out_image = Image.new('RGBA', (24, 12)) - out_image.paste(in_image.crop((2, 2, 26, 14)), (0, 0)) - out_image.save(out_path_wall) - -def hanging_sign_bg_image(material): - in_path = f'{in_dir}/assets/minecraft/textures/gui/hanging_signs/{material}.png' - out_path = f'{out_dir}/bg/{material}_hanging_sign.png' - out_path_wall = f'{out_dir}/bg/{material}_hanging_wall_sign.png' - - in_image = Image.open(in_path) - - out_image = Image.new('RGBA', (16, 14)) - out_image.paste(in_image.crop((0, 2, 16, 16)), (0, 0)) - out_image.save(out_path) - - shutil.copyfile(in_path, out_path_wall) - - -def sign_icon_image(material): - in_path = f'{in_dir}/assets/minecraft/textures/item/{material}_sign.png' - out_path = f'{out_dir}/icon/{material}_sign.png' - out_path_wall = f'{out_dir}/icon/{material}_wall_sign.png' - - in_image = Image.open(in_path) - - out_image = Image.new('RGBA', (13, 14)) - out_image.paste(in_image.crop((2, 2, 15, 16)), (0, 0)) - out_image.save(out_path) - - out_image = Image.new('RGBA', (13, 9)) - out_image.paste(in_image.crop((2, 2, 15, 11)), (0, 0)) - out_image.save(out_path_wall) - - -def hanging_sign_icon_image(material): - in_path = f'{in_dir}/assets/minecraft/textures/item/{material}_hanging_sign.png' - out_path = f'{out_dir}/icon/{material}_hanging_sign.png' - out_path_wall = f'{out_dir}/icon/{material}_hanging_wall_sign.png' - - in_image = Image.open(in_path) - - out_image = Image.new('RGBA', (14, 12)) - out_image.paste(in_image.crop((1, 3, 15, 15)), (0, 0)) - out_image.save(out_path) - - out_image = Image.new('RGBA', (14, 14)) - out_image.paste(in_image.crop((1, 1, 15, 15)), (0, 0)) - out_image.save(out_path_wall) - -for material in MATERIALS: - sign_bg_image(material) - hanging_sign_bg_image(material) - sign_icon_image(material) - hanging_sign_icon_image(material) diff --git a/rustfmt.toml b/rustfmt.toml deleted file mode 100644 index 218e203..0000000 --- a/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -hard_tabs = true diff --git a/src/Buffer.hpp b/src/Buffer.hpp new file mode 100644 index 0000000..9975dcb --- /dev/null +++ b/src/Buffer.hpp @@ -0,0 +1,90 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include +#include +#include + + +namespace MinedMap { + +class Buffer { +private: + const uint8_t *data; + size_t len; + +public: + static uint16_t parse16(const uint8_t *buf) { + return (buf[0] << 8) | buf[1]; + } + + static uint32_t parse32(const uint8_t *buf) { + return (uint32_t(buf[0]) << 24) | (uint32_t(buf[1]) << 16) | (uint32_t(buf[2]) << 8) | uint32_t(buf[3]); + } + + static uint64_t parse64(const uint8_t *buf) { + return (uint64_t(buf[0]) << 56) | (uint64_t(buf[1]) << 48) | (uint64_t(buf[2]) << 40) | (uint64_t(buf[3]) << 32) + | (uint64_t(buf[4]) << 24) | (uint64_t(buf[5]) << 16) | (uint64_t(buf[6]) << 8) | uint64_t(buf[7]); + } + + + Buffer(const uint8_t *data0, size_t len0) : data(data0), len(len0) {} + + size_t getRemaining() const { + return len; + } + + const uint8_t * get(size_t n) { + if (n > len) + throw std::runtime_error("Buffer::get(): buffer underrun"); + + data += n; + len -= n; + return (data - n); + } + + uint8_t get8() { + return *get(1); + } + + uint16_t get16() { + return parse16(get(2)); + } + + uint32_t get32() { + return parse32(get(4)); + } + + uint64_t get64() { + return parse64(get(8)); + } + +}; + +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..1eea2b3 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,40 @@ +include_directories(${ZLIB_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS}) +add_definitions(${PNG_DEFINITIONS}) + +add_executable(MinedMap + MinedMap.cpp + GZip.cpp + Info.cpp + PNG.cpp + + NBT/Tag.cpp + Resource/Biome.cpp + Resource/BlockType.cpp + World/Chunk.cpp + World/ChunkData.cpp + World/Level.cpp + World/Region.cpp + World/Section.cpp +) +set_target_properties(MinedMap PROPERTIES COMPILE_FLAGS "-std=c++11 -Wall") +target_link_libraries(MinedMap ${ZLIB_LIBRARIES} ${PNG_LIBRARIES}) + +add_executable(nbtdump + nbtdump.cpp + GZip.cpp + NBT/Tag.cpp +) +set_target_properties(nbtdump PROPERTIES COMPILE_FLAGS "-std=c++11 -Wall") +target_link_libraries(nbtdump ${ZLIB_LIBRARIES}) + +add_executable(regiondump + regiondump.cpp + GZip.cpp + NBT/Tag.cpp + World/ChunkData.cpp + World/Region.cpp +) +set_target_properties(regiondump PROPERTIES COMPILE_FLAGS "-std=c++11 -Wall") +target_link_libraries(regiondump ${ZLIB_LIBRARIES}) + +install(TARGETS MinedMap RUNTIME DESTINATION bin) diff --git a/src/GZip.cpp b/src/GZip.cpp new file mode 100644 index 0000000..0005923 --- /dev/null +++ b/src/GZip.cpp @@ -0,0 +1,68 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "GZip.hpp" + +#include +#include +#include + + +namespace MinedMap { + +std::vector readGZip(const char *filename) { + std::vector buffer; + size_t len = 0; + + gzFile f = gzopen(filename, "rb"); + if (!f) + throw std::system_error( + errno, std::generic_category(), + (std::string("unable to open file ") + filename).c_str() + ); + + while (true) { + if ((buffer.size() - len) < 4096) + buffer.resize(buffer.size() + 4096); + + int r = gzread(f, buffer.data()+len, buffer.size()-len); + if (r < 0) + throw std::system_error(errno, std::generic_category(), "error reading GZip file"); + + if (!r) + break; + + len += r; + } + + gzclose_r(f); + + buffer.resize(len); + + return buffer; +} + +} diff --git a/src/GZip.hpp b/src/GZip.hpp new file mode 100644 index 0000000..8505039 --- /dev/null +++ b/src/GZip.hpp @@ -0,0 +1,37 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include + + +namespace MinedMap { + +std::vector readGZip(const char *filename); + +} diff --git a/src/Info.cpp b/src/Info.cpp new file mode 100644 index 0000000..eef2b0e --- /dev/null +++ b/src/Info.cpp @@ -0,0 +1,101 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Info.hpp" + +#include +#include +#include +#include + + +namespace MinedMap { + +void Info::writeJSON(const char *filename) const { + const std::string tmpfile = std::string(filename) + ".tmp"; + + FILE *f = std::fopen(tmpfile.c_str(), "w"); + if (!f) { + std::fprintf(stderr, "Unable to open %s: %s\n", tmpfile.c_str(), std::strerror(errno)); + return; + } + + std::fprintf(f, "{\n"); + std::fprintf(f, " \"mipmaps\" : [\n"); + + for (size_t level = 0; level < regions.size(); level++) { + int minX, maxX, minZ, maxZ; + std::tie(minX, maxX, minZ, maxZ) = getBounds(level); + + std::fprintf(f, " {\n"); + std::fprintf(f, " \"info\" : {\n"); + std::fprintf(f, " \"minX\" : %i,\n", minX); + std::fprintf(f, " \"maxX\" : %i,\n", maxX); + std::fprintf(f, " \"minZ\" : %i,\n", minZ); + std::fprintf(f, " \"maxZ\" : %i\n", maxZ); + std::fprintf(f, " },\n"); + std::fprintf(f, " \"regions\" : [\n"); + + for (int z = minZ; z <= maxZ; z++) { + std::fprintf(f, " ["); + + for (int x = minX; x <= maxX; x++) { + std::fprintf(f, "%s", regions[level].count(std::make_pair(x, z)) ? "true" : "false"); + + if (x < maxX) + std::fprintf(f, ", "); + } + + if (z < maxZ) + std::fprintf(f, "],\n"); + else + std::fprintf(f, "]\n"); + } + + std::fprintf(f, " ]\n"); + + if (level < regions.size() - 1) + std::fprintf(f, " },\n"); + else + std::fprintf(f, " }\n"); + } + + std::fprintf(f, " ],\n"); + std::fprintf(f, " \"spawn\" : {\n"); + std::fprintf(f, " \"x\" : %li,\n", (long)spawnX); + std::fprintf(f, " \"z\" : %li\n", (long)spawnZ); + std::fprintf(f, " }\n"); + std::fprintf(f, "}\n"); + + std::fclose(f); + + if (std::rename(tmpfile.c_str(), filename) < 0) { + std::fprintf(stderr, "Unable to save %s: %s\n", filename, std::strerror(errno)); + std::remove(tmpfile.c_str()); + } +} + +} diff --git a/src/Info.hpp b/src/Info.hpp new file mode 100644 index 0000000..4bc1222 --- /dev/null +++ b/src/Info.hpp @@ -0,0 +1,83 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +namespace MinedMap { + +class Info { +private: + std::vector>> regions; + std::vector> bounds; + + int32_t spawnX, spawnZ; + +public: + Info() : spawnX(0), spawnZ(0) { + addMipmapLevel(); + } + + std::tuple getBounds(size_t level) const { + return bounds[level]; + } + + void addRegion(int x, int z, size_t level) { + regions[level].insert(std::make_pair(x, z)); + + std::tuple &b = bounds[level]; + + if (x < std::get<0>(b)) std::get<0>(b) = x; + if (x > std::get<1>(b)) std::get<1>(b) = x; + if (z < std::get<2>(b)) std::get<2>(b) = z; + if (z > std::get<3>(b)) std::get<3>(b) = z; + } + + void addMipmapLevel() { + regions.emplace_back(); + bounds.emplace_back(INT_MAX, INT_MIN, INT_MAX, INT_MIN); + } + + size_t getMipmapLevel() const { + return regions.size()-1; + } + + void setSpawn(const std::pair &v) { + std::tie(spawnX, spawnZ) = v; + } + + void writeJSON(const char *filename) const; +}; + +} diff --git a/src/MinedMap.cpp b/src/MinedMap.cpp new file mode 100644 index 0000000..f37b96c --- /dev/null +++ b/src/MinedMap.cpp @@ -0,0 +1,526 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Info.hpp" +#include "PNG.hpp" +#include "World/Level.hpp" +#include "World/Region.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + + +namespace MinedMap { + +static const int BIOME_SMOOTH = 3; +static const size_t DIM = World::Region::SIZE*World::Chunk::SIZE; + + +static void addChunkBiome(uint8_t biomemap[DIM*DIM], size_t X, size_t Z, const World::ChunkData *data) { + World::Chunk chunk(data); + World::Chunk::Heightmap layer = chunk.getTopLayer(false); + + for (size_t x = 0; x < World::Chunk::SIZE; x++) { + for (size_t z = 0; z < World::Chunk::SIZE; z++) { + size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x; + const World::Chunk::Height &height = layer.v[x][z]; + biomemap[i] = chunk.getBiome(x, height.y, z); + } + } +} + +static uint8_t biomeAt(ssize_t x, ssize_t z, const std::unique_ptr biomemaps[3][3]) { + size_t a = 1, b = 1; + + if (x < 0) { + a--; + x += DIM; + } else if (x >= (ssize_t)DIM) { + a++; + x -= DIM; + } + if (z < 0) { + b--; + z += DIM; + } else if (z >= (ssize_t)DIM) { + b++; + z -= DIM; + } + + return biomemaps[a][b].get()[z*DIM + x]; +} + +static Resource::Color collectColors(size_t x, size_t z, const World::Block &block, const std::unique_ptr biomemaps[3][3]) { + std::unordered_map biomes; + for (int dx = -BIOME_SMOOTH; dx <= BIOME_SMOOTH; dx++) { + for (int dz = -BIOME_SMOOTH; dz <= BIOME_SMOOTH; dz++) { + if (std::abs(dx) + std::abs(dz) > BIOME_SMOOTH) + continue; + + uint8_t biome = biomeAt(x+dx, z+dz, biomemaps); + if (biomes.count(biome)) + biomes[biome]++; + else + biomes[biome] = 1; + } + } + + Resource::FloatColor c = {}; + size_t total = 0; + + for (const auto &e : biomes) { + uint8_t biome = e.first; + size_t count = e.second; + + if (biome == 0xff) + continue; + + c = c + count * block.getColor(biome); + total += count; + } + + if (!total) + return block.getColor(0); + + return (1.0f / total) * c; +} + +static void addChunk(Resource::Color image[DIM*DIM], uint8_t lightmap[2*DIM*DIM], size_t X, size_t Z, + const World::ChunkData *data, const std::unique_ptr biomemaps[3][3] +) { + World::Chunk chunk(data); + World::Chunk::Heightmap layer = chunk.getTopLayer(true); + + for (size_t x = 0; x < World::Chunk::SIZE; x++) { + for (size_t z = 0; z < World::Chunk::SIZE; z++) { + size_t i = (Z*World::Chunk::SIZE+z)*DIM + X*World::Chunk::SIZE+x; + const World::Chunk::Height &height = layer.v[x][z]; + World::Block block = chunk.getBlock(x, height, z); + + if (!block.isVisible()) + continue; + + image[i] = collectColors(X*World::Chunk::SIZE+x, Z*World::Chunk::SIZE+z, block, biomemaps); + lightmap[2*i+1] = (1 - block.blockLight/15.f)*192; + } + } +} + +static int64_t readStamp(const std::string &filename) { + int64_t v = INT64_MIN; + + std::FILE *f = std::fopen((filename + ".stamp").c_str(), "r"); + if (f) { + std::fscanf(f, "%" SCNd64, &v); + std::fclose(f); + } + + return v; +} + +static void writeStamp(const std::string &filename, int64_t v) { + std::FILE *f = std::fopen((filename + ".stamp").c_str(), "w"); + if (f) { + std::fprintf(f, "%" PRId64, v); + std::fclose(f); + } +} + +static bool writeImage(const std::string &output, const uint8_t *data, PNG::Format format, int64_t t) { + const std::string tmpfile = output + ".tmp"; + + size_t len = PNG::formatBytes(format)*DIM*DIM; + bool changed = true; + + try { + std::unique_ptr old(new uint8_t[len]); + PNG::read(output.c_str(), old.get(), DIM, DIM, format); + + if (std::memcmp(data, old.get(), len) == 0) + changed = false; + } catch (const std::exception& ex) { + } + + try { + if (changed) { + PNG::write(tmpfile.c_str(), data, DIM, DIM, format); + + if (std::rename(tmpfile.c_str(), output.c_str()) < 0) { + std::fprintf(stderr, "Unable to save %s: %s\n", output.c_str(), std::strerror(errno)); + std::remove(tmpfile.c_str()); + } + } + + writeStamp(output, t); + } catch (const std::exception& ex) { + std::remove(tmpfile.c_str()); + throw; + } + + return changed; +} + +static int64_t getModTime(const std::string &file) { + struct stat s; + if (stat(file.c_str(), &s) < 0) { + if (errno != ENOENT) + std::fprintf(stderr, "Unable to stat %s: %s\n", file.c_str(), std::strerror(errno)); + return INT64_MIN; + } + +#ifdef _WIN32 + return (int64_t)s.st_mtime * 1000000; +#else + return (int64_t)s.st_mtim.tv_sec * 1000000 + s.st_mtim.tv_nsec / 1000; +#endif +} + +static bool checkRegion(int64_t changed, const std::string &file) { + struct stat s; + if (stat(file.c_str(), &s) < 0) + return true; + + int64_t outtime = readStamp(file); + if (changed <= outtime) { + std::printf("%s is up-to-date.\n", file.c_str()); + return false; + } + + return true; +} + +template +static std::string format(const T &v) { + std::ostringstream s; + + s << v; + return s.str(); +} + +static std::string formatTileName(int x, int z, const std::string &ext) { + std::ostringstream s; + + s << "r." << x << "." << z << "." << ext; + return s.str(); +} + +static bool checkFilename(const char *name, int *x, int *z) { + if (std::sscanf(name, "r.%i.%i.mca", x, z) != 2) + return false; + + return (std::string(name) == formatTileName(*x, *z, "mca")); +} + +static void makeDir(const std::string &name) { + if ( + mkdir( + name.c_str() +#ifndef _WIN32 + , 0777 +#endif + ) < 0 && errno != EEXIST + ) + throw std::system_error(errno, std::generic_category(), "unable to create directory " + name); +} + +static void makeBiome(const std::string ®iondir, const std::string &outputdir, int x, int z) { + std::string inname = formatTileName(x, z, "mca"); + std::string outname = formatTileName(x, z, "png"); + std::string input = regiondir + "/" + inname, output = outputdir + "/biome/" + outname; + + int64_t intime = getModTime(input); + if (intime == INT64_MIN) + return; + + if (!checkRegion(intime, output)) + return; + + std::printf("Generating %s from %s... ", output.c_str(), input.c_str()); + std::fflush(stdout); + + try { + std::unique_ptr biomemap(new uint8_t[DIM*DIM]); + std::memset(biomemap.get(), 0xff, DIM*DIM); + + World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) { + addChunkBiome(biomemap.get(), X, Z, chunk); + }); + + bool changed = writeImage(output, biomemap.get(), PNG::GRAY, intime); + std::printf("%s.\n", changed ? "done" : "unchanged"); + } catch (const std::exception& ex) { + std::fprintf(stderr, "Failed to generate %s: %s\n", output.c_str(), ex.what()); + } +} + +static void makeBiomes(const std::string ®iondir, const std::string &outputdir, const Info *info) { + int minX, maxX, minZ, maxZ; + std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0); + + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) + makeBiome(regiondir, outputdir, x, z); + } +} + +static void makeMap(const std::string ®iondir, const std::string &outputdir, int x, int z) { + std::string inname = formatTileName(x, z, "mca"); + std::string outname = formatTileName(x, z, "png"); + std::string input = regiondir + "/" + inname; + std::string output = outputdir + "/map/0/" + outname, output_light = outputdir + "/light/0/" + outname; + std::string biomenames[3][3]; + + int64_t intime = getModTime(input); + if (intime == INT64_MIN) + return; + + for (size_t i = 0; i < 3; i++) { + for (size_t j = 0; j < 3; j++) { + biomenames[i][j] = outputdir + "/biome/" + formatTileName(x + i - 1, z + j - 1, "png"); + intime = std::max(intime, getModTime(biomenames[i][j])); + } + } + + if (!checkRegion(intime, output)) + return; + + std::printf("Generating %s from %s... ", output.c_str(), input.c_str()); + std::fflush(stdout); + + try { + std::unique_ptr biomemaps[3][3]; + for (size_t i = 0; i < 3; i++) { + for (size_t j = 0; j < 3; j++) { + biomemaps[i][j].reset(new uint8_t[DIM*DIM]); + std::memset(biomemaps[i][j].get(), 0, DIM*DIM); + + try { + PNG::read(biomenames[i][j].c_str(), biomemaps[i][j].get(), DIM, DIM, PNG::GRAY); + } catch (const std::exception& ex) {} + } + } + + std::unique_ptr image(new Resource::Color[DIM*DIM]); + + std::unique_ptr lightmap(new uint8_t[2*DIM*DIM]); + std::memset(lightmap.get(), 0, 2*DIM*DIM); + + World::Region::visitChunks(input.c_str(), [&] (size_t X, size_t Z, const World::ChunkData *chunk) { + addChunk(image.get(), lightmap.get(), X, Z, chunk, biomemaps); + }); + + bool changed = writeImage(output, reinterpret_cast(image.get()), PNG::RGB_ALPHA, intime); + changed = writeImage(output_light, lightmap.get(), PNG::GRAY_ALPHA, intime) || changed; + std::printf("%s.\n", changed ? "done" : "unchanged"); + } catch (const std::exception& ex) { + std::fprintf(stderr, "Failed to generate %s: %s\n", output.c_str(), ex.what()); + } +} + +static void makeMaps(const std::string ®iondir, const std::string &outputdir, const Info *info) { + int minX, maxX, minZ, maxZ; + std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0); + + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) + makeMap(regiondir, outputdir, x, z); + } +} + +static bool makeMipmap(const std::string &dir, size_t level, int x, int z, PNG::Format imageFormat) { + bool ret = false; + + std::string indir = dir + "/" + format(level-1) + "/"; + std::string outdir = dir + "/" + format(level) + "/"; + + const std::string nw_str = indir + formatTileName(x*2, z*2, "png"); + const std::string ne_str = indir + formatTileName(x*2+1, z*2, "png"); + const std::string sw_str = indir + formatTileName(x*2, z*2+1, "png"); + const std::string se_str = indir + formatTileName(x*2+1, z*2+1, "png"); + + const char *nw = nw_str.c_str(); + const char *ne = ne_str.c_str(); + const char *sw = sw_str.c_str(); + const char *se = se_str.c_str(); + + int64_t t = INT64_MIN; + size_t count = 0; + for (auto name : {&nw, &ne, &sw, &se}) { + struct stat s; + if (stat(*name, &s) < 0) { + *name = nullptr; + continue; + } + + int64_t t_part = readStamp(*name); + if (t_part > t) + t = t_part; + + count++; + } + + std::string output = outdir + formatTileName(x, z, "png"); + + { + struct stat s; + if (stat(output.c_str(), &s) == 0) { + ret = true; + + int64_t outtime = readStamp(output); + if (t <= outtime) + return ret; + } + } + + if (!count) + return ret; + + const std::string tmpfile = output + ".tmp"; + + try { + PNG::mipmap(tmpfile.c_str(), DIM, DIM, imageFormat, nw, ne, sw, se); + + if (std::rename(tmpfile.c_str(), output.c_str()) < 0) { + std::fprintf(stderr, "Unable to save %s: %s\n", output.c_str(), std::strerror(errno)); + std::remove(tmpfile.c_str()); + } + + writeStamp(output, t); + } catch (const std::exception& ex) { + std::remove(tmpfile.c_str()); + throw; + } + + return true; +} + +static void makeMipmaps(const std::string &dir, Info *info) { + int minX, maxX, minZ, maxZ; + std::tie(minX, maxX, minZ, maxZ) = info->getBounds(0); + + while (minX < -1 || maxX > 0 || minZ < -1 || maxZ > 0) { + info->addMipmapLevel(); + size_t level = info->getMipmapLevel(); + makeDir(dir + "/map/" + format(level)); + makeDir(dir + "/light/" + format(level)); + + minX = (minX-1)/2; + maxX = maxX/2; + minZ = (minZ-1)/2; + maxZ = maxZ/2; + + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + if (makeMipmap(dir + "/map", level, x, z, PNG::RGB_ALPHA)) + info->addRegion(x, z, level); + + makeMipmap(dir + "/light", level, x, z, PNG::GRAY_ALPHA); + } + } + } +} + +static Info collectInfo(const std::string ®iondir) { + DIR *dir = opendir(regiondir.c_str()); + if (!dir) + throw std::system_error(errno, std::generic_category(), "Unable to read input directory"); + + Info info; + + struct dirent *entry; + while ((entry = readdir(dir)) != nullptr) { + int x, z; + if (!checkFilename(entry->d_name, &x, &z)) + continue; + + info.addRegion(x, z, 0); + + } + + closedir(dir); + + return info; +} + +static void doLevel(const std::string &inputdir, const std::string &outputdir) { + const std::string regiondir = inputdir + "/region"; + + makeDir(outputdir + "/biome"); + makeDir(outputdir + "/map"); + makeDir(outputdir + "/map/0"); + makeDir(outputdir + "/light"); + makeDir(outputdir + "/light/0"); + + Info info = collectInfo(regiondir); + + std::printf("Updating biome data...\n"); + makeBiomes(regiondir, outputdir, &info); + + std::printf("Updating map data...\n"); + makeMaps(regiondir, outputdir, &info); + + World::Level level((inputdir + "/level.dat").c_str()); + info.setSpawn(level.getSpawn()); + + std::printf("Updating mipmaps...\n"); + makeMipmaps(outputdir, &info); + + info.writeJSON((outputdir + "/info.json").c_str()); +} + +} + + +int main(int argc, char *argv[]) { + if (argc < 3) { + std::fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + try { + MinedMap::doLevel(argv[1], argv[2]); + } catch (const std::runtime_error& ex) { + std::fprintf(stderr, "Error: %s\n", ex.what()); + return 1; + } + + return 0; +} diff --git a/src/NBT/ByteArrayTag.hpp b/src/NBT/ByteArrayTag.hpp new file mode 100644 index 0000000..95e9ddb --- /dev/null +++ b/src/NBT/ByteArrayTag.hpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + +#include + + +namespace MinedMap { +namespace NBT { + +class ByteArrayTag : public Tag { +private: + uint32_t len; + const uint8_t *ptr; + +public: + static const MakeType Type; + + + ByteArrayTag(Buffer *buffer) { + len = buffer->get32(); + ptr = buffer->get(len); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &indent) const { + os << "(" << len << ") [" << std::endl; + + std::string inner = indent + " "; + + for (size_t i = 0; i < len; i++) { + uint8_t v = ptr[i]; + + os << inner + << (unsigned)v << " / " + << (int)(int8_t)v << " / " + << std::hex << "0x" << (unsigned)v << std::dec + << std::endl; + } + + os << indent << "]"; + } + + uint32_t getLength() const { + return len; + } + + const uint8_t * getPointer() const { + return ptr; + } + + uint8_t getValue(size_t i) const { + return ptr[i]; + } +}; + +} +} diff --git a/src/NBT/ByteTag.hpp b/src/NBT/ByteTag.hpp new file mode 100644 index 0000000..c578b9c --- /dev/null +++ b/src/NBT/ByteTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class ByteTag : public Tag { +private: + uint8_t value; + +public: + static const MakeType Type; + + + ByteTag(Buffer *buffer) { + value = buffer->get8(); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + os << (unsigned)getValue() << " / " + << (int)(int8_t)getValue() << " / " + << std::hex << "0x" << (unsigned)getValue() << std::dec; + } + + uint8_t getValue() const { + return value; + } +}; + +} +} diff --git a/src/NBT/CompoundTag.hpp b/src/NBT/CompoundTag.hpp new file mode 100644 index 0000000..2d3fcbe --- /dev/null +++ b/src/NBT/CompoundTag.hpp @@ -0,0 +1,82 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "EndTag.hpp" +#include "Tag.hpp" + +#include +#include + + +namespace MinedMap { +namespace NBT { + +class CompoundTag : public Tag, public std::unordered_map> { +public: + static const MakeType Type; + + + CompoundTag(Buffer *buffer) { + while (true) { + std::pair> v = Tag::readNamedTag(buffer); + if (v.second->getType() == EndTag::Type) + break; + + insert(std::move(v)); + } + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &indent) const { + os << "{" << std::endl; + + std::string inner = indent + " "; + + for (const auto &item : *this) { + os << inner << item.first << ": " << item.second->getType() << " "; + item.second->print(os, inner); + os << std::endl; + } + + os << indent << "}"; + } + + template std::shared_ptr get(const std::string &key) const { + auto it = find(key); + if (it == end()) + return std::shared_ptr(); + + return std::dynamic_pointer_cast(it->second); + } +}; + +} +} diff --git a/src/NBT/DoubleTag.hpp b/src/NBT/DoubleTag.hpp new file mode 100644 index 0000000..b83efe2 --- /dev/null +++ b/src/NBT/DoubleTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class DoubleTag : public Tag { +private: + const uint8_t *ptr; + +public: + static const MakeType Type; + + + DoubleTag(Buffer *buffer) { + ptr = buffer->get(8); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + union { + uint64_t i; + double d; + }; + + i = Buffer::parse64(ptr); + os << d; + } +}; + +} +} diff --git a/src/NBT/EndTag.hpp b/src/NBT/EndTag.hpp new file mode 100644 index 0000000..167412a --- /dev/null +++ b/src/NBT/EndTag.hpp @@ -0,0 +1,51 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class EndTag : public Tag { +public: + static const MakeType Type; + + + EndTag(Buffer *) {} + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream&, const std::string &) const { + } +}; + +} +} diff --git a/src/NBT/FloatTag.hpp b/src/NBT/FloatTag.hpp new file mode 100644 index 0000000..8748bc6 --- /dev/null +++ b/src/NBT/FloatTag.hpp @@ -0,0 +1,62 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class FloatTag : public Tag { + const uint8_t *ptr; + +public: + static const MakeType Type; + + + FloatTag(Buffer *buffer) { + ptr = buffer->get(4); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + union { + uint32_t i; + float f; + }; + + i = Buffer::parse32(ptr); + os << f; + } +}; + +} +} diff --git a/src/NBT/IntArrayTag.hpp b/src/NBT/IntArrayTag.hpp new file mode 100644 index 0000000..4dfcd05 --- /dev/null +++ b/src/NBT/IntArrayTag.hpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + +#include + + +namespace MinedMap { +namespace NBT { + +class IntArrayTag : public Tag { +private: + uint32_t len; + const uint8_t *ptr; + +public: + static const MakeType Type; + + + IntArrayTag(Buffer *buffer) { + len = buffer->get32(); + ptr = buffer->get(4*len); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &indent) const { + os << "(" << len << ") [" << std::endl; + + std::string inner = indent + " "; + + for (size_t i = 0; i < len; i++) { + uint32_t v = getValue(i); + + os << inner + << v << " / " + << (int32_t)v << " / " + << std::hex << "0x" << v << std::dec + << std::endl; + } + + os << indent << "]"; + } + + uint32_t getLength() const { + return len; + } + + const uint8_t * getPointer() const { + return ptr; + } + + uint32_t getValue(size_t i) const { + return Buffer::parse32(&ptr[4*i]); + } +}; + +} +} diff --git a/src/NBT/IntTag.hpp b/src/NBT/IntTag.hpp new file mode 100644 index 0000000..e6babd0 --- /dev/null +++ b/src/NBT/IntTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class IntTag : public Tag { +private: + const uint8_t *ptr; + +public: + static const MakeType Type; + + + IntTag(Buffer *buffer) { + ptr = buffer->get(4); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + os << getValue() << " / " + << (int32_t)getValue() << " / " + << std::hex << "0x" << getValue() << std::dec; + } + + uint32_t getValue() const { + return Buffer::parse32(ptr); + } +}; + +} +} diff --git a/src/NBT/ListTag.hpp b/src/NBT/ListTag.hpp new file mode 100644 index 0000000..7276923 --- /dev/null +++ b/src/NBT/ListTag.hpp @@ -0,0 +1,78 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + +#include + + +namespace MinedMap { +namespace NBT { + +class ListTag : public Tag, public std::vector> { +private: + const TagType *subtype; + +public: + static const MakeType Type; + + + ListTag(Buffer *buffer) { + subtype = &getTypeById(buffer->get8()); + + uint32_t len = buffer->get32(); + + for (uint32_t i = 0; i < len; i++) + push_back(subtype->read(buffer)); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual const TagType & getSubtype() const { + return *subtype; + } + + virtual void print(std::ostream& os, const std::string &indent) const { + os << getSubtype() << " [" << std::endl; + + std::string inner = indent + " "; + + for (const auto &item : *this) { + os << inner; + item->print(os, inner); + os << std::endl; + } + + os << indent << "]"; + } +}; + +} +} diff --git a/src/NBT/LongArrayTag.hpp b/src/NBT/LongArrayTag.hpp new file mode 100644 index 0000000..2e24d5a --- /dev/null +++ b/src/NBT/LongArrayTag.hpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + +#include + + +namespace MinedMap { +namespace NBT { + +class LongArrayTag : public Tag { +private: + uint32_t len; + const uint8_t *ptr; + +public: + static const MakeType Type; + + + LongArrayTag(Buffer *buffer) { + len = buffer->get32(); + ptr = buffer->get(8*len); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &indent) const { + os << "(" << len << ") [" << std::endl; + + std::string inner = indent + " "; + + for (size_t i = 0; i < len; i++) { + uint64_t v = Buffer::parse64(&ptr[8*i]); + + os << inner + << v << " / " + << (int64_t)v << " / " + << std::hex << "0x" << v << std::dec + << std::endl; + } + + os << indent << "]"; + } + + uint32_t getLength() const { + return len; + } + + const uint8_t * getPointer() const { + return ptr; + } + + uint64_t getValue(size_t i) const { + return Buffer::parse64(&ptr[8*i]); + } +}; + +} +} diff --git a/src/NBT/LongTag.hpp b/src/NBT/LongTag.hpp new file mode 100644 index 0000000..05f6bc2 --- /dev/null +++ b/src/NBT/LongTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class LongTag : public Tag { +private: + const uint8_t *ptr; + +public: + static const MakeType Type; + + + LongTag(Buffer *buffer) { + ptr = buffer->get(8); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + os << getValue() << " / " + << (int64_t)getValue() << " / " + << std::hex << "0x" << getValue() << std::dec; + } + + uint64_t getValue() const { + return Buffer::parse64(ptr); + } +}; + +} +} diff --git a/src/NBT/ShortTag.hpp b/src/NBT/ShortTag.hpp new file mode 100644 index 0000000..593a1ed --- /dev/null +++ b/src/NBT/ShortTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class ShortTag : public Tag { +private: + const uint8_t *ptr; + +public: + static const MakeType Type; + + + ShortTag(Buffer *buffer) { + ptr = buffer->get(2); + } + + virtual const TagType & getType() const { + return Type; + } + + virtual void print(std::ostream& os, const std::string &) const { + os << getValue() << " / " + << (int16_t)getValue() << " / " + << std::hex << "0x" << getValue() << std::dec; + } + + uint16_t getValue() const { + return Buffer::parse16(ptr); + } +}; + +} +} diff --git a/src/NBT/StringTag.hpp b/src/NBT/StringTag.hpp new file mode 100644 index 0000000..6fb2b41 --- /dev/null +++ b/src/NBT/StringTag.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Tag.hpp" + + +namespace MinedMap { +namespace NBT { + +class StringTag : public Tag { +private: + uint16_t len; + const uint8_t *ptr; + +public: + static const MakeType Type; + + + StringTag(Buffer *buffer) { + len = buffer->get16(); + ptr = buffer->get(len); + } + + virtual const TagType & getType() const { + return Type; + } + + std::string getValue() const { + return std::string(reinterpret_cast(ptr), len); + } + + virtual void print(std::ostream& os, const std::string &) const { + os << "\"" << getValue() << "\""; + } +}; + +} +} diff --git a/src/NBT/Tag.cpp b/src/NBT/Tag.cpp new file mode 100644 index 0000000..e8c429f --- /dev/null +++ b/src/NBT/Tag.cpp @@ -0,0 +1,91 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Tag.hpp" + +#include "EndTag.hpp" +#include "ByteTag.hpp" +#include "ShortTag.hpp" +#include "IntTag.hpp" +#include "LongTag.hpp" +#include "FloatTag.hpp" +#include "DoubleTag.hpp" +#include "ByteArrayTag.hpp" +#include "StringTag.hpp" +#include "ListTag.hpp" +#include "CompoundTag.hpp" +#include "IntArrayTag.hpp" +#include "LongArrayTag.hpp" + + +namespace MinedMap { +namespace NBT { + +const Tag::MakeType EndTag::Type("End"); +const Tag::MakeType ByteTag::Type("Byte"); +const Tag::MakeType ShortTag::Type("Short"); +const Tag::MakeType IntTag::Type("Int"); +const Tag::MakeType LongTag::Type("Long"); +const Tag::MakeType FloatTag::Type("Float"); +const Tag::MakeType DoubleTag::Type("Double"); +const Tag::MakeType ByteArrayTag::Type("ByteArray"); +const Tag::MakeType StringTag::Type("String"); +const Tag::MakeType ListTag::Type("List"); +const Tag::MakeType CompoundTag::Type("Compound"); +const Tag::MakeType IntArrayTag::Type("IntArray"); +const Tag::MakeType LongArrayTag::Type("LongArray"); + + +const std::vector Tag::types = { + &EndTag::Type, + &ByteTag::Type, + &ShortTag::Type, + &IntTag::Type, + &LongTag::Type, + &FloatTag::Type, + &DoubleTag::Type, + &ByteArrayTag::Type, + &StringTag::Type, + &ListTag::Type, + &CompoundTag::Type, + &IntArrayTag::Type, + &LongArrayTag::Type, +}; + + +std::pair> Tag::readNamedTag(Buffer *buffer) { + const TagType &type = getTypeById(buffer->get8()); + if (type == EndTag::Type) + return std::make_pair("", std::make_shared(buffer)); + + uint16_t len = buffer->get16(); + std::string name(reinterpret_cast(buffer->get(len)), len); + + return std::make_pair(name, type.read(buffer)); +} + +} +} diff --git a/src/NBT/Tag.hpp b/src/NBT/Tag.hpp new file mode 100644 index 0000000..3fb824b --- /dev/null +++ b/src/NBT/Tag.hpp @@ -0,0 +1,103 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include +#include +#include + +#include "../Buffer.hpp" + + +namespace MinedMap { +namespace NBT { + +class Tag; + +class TagType { +public: + TagType() = default; + TagType(const TagType&) = delete; + TagType & operator=(const TagType&) = delete; + + virtual const char * getName() const = 0; + virtual std::shared_ptr read(Buffer *buffer) const = 0; + + bool operator==(const TagType &type) const { + return this == &type; + } +}; + +class Tag { +private: + static const std::vector types; + +protected: + template + class MakeType : public TagType { + private: + const char *name; + + public: + MakeType(const char *name0) : name(name0) {} + + virtual const char * getName() const { + return name; + } + + virtual std::shared_ptr read(Buffer *buffer) const { + return std::make_shared(buffer); + } + }; + + + static const TagType & getTypeById(uint8_t id) { + return *types.at(id); + } + +public: + static std::pair> readNamedTag(Buffer *buffer); + + virtual const TagType & getType() const = 0; + virtual void print(std::ostream& os, const std::string &indent) const = 0; + + virtual ~Tag() {} +}; + +static inline std::ostream& operator<<(std::ostream& os, const TagType &type) { + return os << type.getName(); +} + +static inline std::ostream& operator<<(std::ostream& os, const Tag &tag) { + os << tag.getType() << " "; + tag.print(os, ""); + return os; +} + +} +} diff --git a/src/PNG.cpp b/src/PNG.cpp new file mode 100644 index 0000000..4e12608 --- /dev/null +++ b/src/PNG.cpp @@ -0,0 +1,162 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "PNG.hpp" + +#include +#include +#include +#include +#include + +#include + + +namespace MinedMap { +namespace PNG { + +static const int formatColorTypes[] = { + [RGB_ALPHA] = PNG_COLOR_TYPE_RGB_ALPHA, + [GRAY_ALPHA] = PNG_COLOR_TYPE_GRAY_ALPHA, + [GRAY] = PNG_COLOR_TYPE_GRAY, +}; + +void write(const char *filename, const uint8_t *data, size_t width, size_t height, Format format) { + std::FILE *f = std::fopen(filename, "wb"); + if (!f) + throw std::system_error(errno, std::generic_category(), "unable to open PNG file"); + + png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) + throw std::runtime_error("unable to create PNG write struct"); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, nullptr); + throw std::runtime_error("unable to create PNG info struct"); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + std::fclose(f); + throw std::runtime_error("unable to write PNG file"); + } + + png_init_io(png_ptr, f); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, formatColorTypes[format], + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + uint8_t *row_pointers[height]; + for (size_t i = 0; i < height; i++) + row_pointers[i] = const_cast(&data[formatBytes(format)*i*width]); + + png_set_rows(png_ptr, info_ptr, row_pointers); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); + + png_destroy_write_struct(&png_ptr, &info_ptr); + std::fclose(f); +} + +void read(const char *filename, uint8_t *data, size_t width, size_t height, Format format) { + std::FILE *f = std::fopen(filename, "rb"); + if (!f) + throw std::system_error(errno, std::generic_category(), "unable to open PNG file"); + + png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) + throw std::runtime_error("unable to create PNG read struct"); + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + throw std::runtime_error("unable to create PNG info struct"); + } + + png_infop end_info = png_create_info_struct(png_ptr); + if (!end_info) { + png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); + throw std::runtime_error("unable to create PNG info struct"); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + fclose(f); + throw std::runtime_error("unable to read PNG file"); + } + + png_init_io(png_ptr, f); + + png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); + + if (png_get_image_width(png_ptr, info_ptr) != width + || png_get_image_height(png_ptr, info_ptr) != height + || png_get_bit_depth(png_ptr, info_ptr) != 8 + || png_get_color_type(png_ptr, info_ptr) != formatColorTypes[format]) + longjmp(png_jmpbuf(png_ptr), 1); + + uint8_t **row_pointers = png_get_rows(png_ptr, info_ptr); + for (size_t i = 0; i < height; i++) + std::memcpy(&data[formatBytes(format)*i*width], row_pointers[i], formatBytes(format)*width); + + png_destroy_read_struct(&png_ptr, &info_ptr, &end_info); + std::fclose(f); +} + +static void readScaled(uint8_t *data, size_t offset_w, size_t offset_h, const char *file, size_t width, size_t height, Format format) { + if (!file) + return; + + size_t b = formatBytes(format); + + std::unique_ptr input(new uint8_t[b*width*height]); + read(file, input.get(), width, height, format); + + for (size_t h = 0; h < width/2; h++) { + for (size_t w = 0; w < width/2; w++) { + for (size_t c = 0; c < b; c++) { + size_t i = 2*b*(width*h + w) + c; + data[b*(width*(offset_h+h) + offset_w+w) + c] = (input[i] + input[i+b] + input[i+b*width] + input[i+b*width+b])/4; + } + } + } +} + +void mipmap(const char *output, size_t width, size_t height, Format format, const char *nw, const char *ne, const char *sw, const char *se) { + size_t size = formatBytes(format)*width*height; + std::unique_ptr data(new uint8_t[size]); + std::memset(data.get(), 0, size); + + readScaled(data.get(), 0, 0, nw, width, height, format); + readScaled(data.get(), width/2, 0, ne, width, height, format); + readScaled(data.get(), 0, height/2, sw, width, height, format); + readScaled(data.get(), width/2, height/2, se, width, height, format); + + write(output, data.get(), width, height, format); +} + +} +} diff --git a/src/PNG.hpp b/src/PNG.hpp new file mode 100644 index 0000000..b1a66dd --- /dev/null +++ b/src/PNG.hpp @@ -0,0 +1,57 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include + + +namespace MinedMap { +namespace PNG { + +enum Format { + RGB_ALPHA, + GRAY_ALPHA, + GRAY, +}; + +static inline size_t formatBytes(Format format) { + const size_t data[] = { + [RGB_ALPHA] = 4, + [GRAY_ALPHA] = 2, + [GRAY] = 1, + }; + + return data[format]; +} + +void write(const char *filename, const uint8_t *data, size_t width, size_t height, Format format); +void read(const char *filename, uint8_t *data, size_t width, size_t height, Format format); +void mipmap(const char *output, size_t width, size_t height, Format format, const char *nw, const char *ne, const char *sw, const char *se); + +} +} diff --git a/src/Resource/Biome.cpp b/src/Resource/Biome.cpp new file mode 100644 index 0000000..440b1d4 --- /dev/null +++ b/src/Resource/Biome.cpp @@ -0,0 +1,348 @@ +/* + Copyright (c) 2015, 2018, Matthias Schiffer + Copyright (c) 2019, Roman Shishkin + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Biome.hpp" + +#include "BlockType.hpp" +#include "../Util.hpp" + + +namespace MinedMap { +namespace Resource { + +static FloatColor colorFromParams(float temp, float rain, bool grass) { + const FloatColor grassColors[3] = { + {0.502f, 0.706f, 0.592f}, // lower right + {0.247f, 0.012f, -0.259f}, // lower left - lower right + {-0.471f, 0.086f, -0.133f}, // upper left - lower left + }; + const FloatColor foliageColors[3] = { + {0.376f, 0.631f, 0.482f}, // lower right + {0.306f, 0.012f, -0.317f}, // lower left - lower right + {-0.580f, 0.106f, -0.165f}, // upper left - lower left + }; + + const FloatColor *colors = grass ? grassColors : foliageColors; + + return colors[0] + temp*colors[1] + rain*colors[2]; +} + + +FloatColor Biome::getGrassColor(float temp, float rain) const { + return colorFromParams(temp, rain, true); +} + +FloatColor Biome::getFoliageColor(float temp, float rain) const { + return colorFromParams(temp, rain, false); +} + + +FloatColor Biome::getBlockColor(const BlockType *type, unsigned height) const { + FloatColor c = { + float(type->color.r), + float(type->color.g), + float(type->color.b), + }; + + float t = clamp(temp - std::max(0.0f, (height-64)/600.0f), 0, 1); + float r = clamp(rain, 0, 1) * t; + + if (type->flags & BLOCK_GRASS) + c *= getGrassColor(t, r); + if (type->flags & BLOCK_FOLIAGE) + c *= getFoliageColor(t, r); + if (type->flags & BLOCK_BIRCH) + c *= FloatColor {0.380f, 0.600f, 0.380f}; + if (type->flags & BLOCK_SPRUCE) + c *= FloatColor {0.502f, 0.655f, 0.333f}; + if (type->flags & BLOCK_WATER) + c *= getWaterColor(); + + float h = 0.5f + height * 0.005f; + + c.r = clamp(c.r * h, 0, 255); + c.g = clamp(c.g * h, 0, 255); + c.b = clamp(c.b * h, 0, 255); + + return c; +} + + +class SwampBiome : public Biome { +protected: + virtual FloatColor getGrassColor(float, float) const { + return {0.417f, 0.439f, 0.224f}; + } + virtual FloatColor getFoliageColor(float temp, float rain) const { + return getGrassColor(temp, rain); + } + +public: + SwampBiome(float temp0, float rain0, FloatColor water0) : + Biome(temp0, rain0, water0) {} +}; + +class DarkForestBiome : public Biome { +private: + const FloatColor darkGreen = {0.157f, 0.204f, 0.039f}; + +protected: + virtual FloatColor getGrassColor(float temp, float rain) const { + return 0.5 * (darkGreen + colorFromParams(temp, rain, true)); + } + + virtual FloatColor getFoliageColor(float temp, float rain) const { + return 0.5 * (darkGreen + colorFromParams(temp, rain, false)); + } + +public: + DarkForestBiome(float temp0, float rain0) : Biome(temp0, rain0) {} +}; + +class BadlandsBiome : public Biome { +protected: + virtual FloatColor getGrassColor(float, float) const { + return {0.565f, 0.506f, 0.302f}; + } + virtual FloatColor getFoliageColor(float, float) const { + return {0.620f, 0.506f, 0.302f}; + } + +public: + BadlandsBiome(float temp0, float rain0) : Biome(temp0, rain0) {} +}; + + +/* Values from https://github.com/erich666/Mineways/blob/master/Win/biomes.cpp */ + +static const Biome BiomeDefault(0.5f, 0.5f); +static const Biome BiomePlains(0.8f, 0.4f); +static const Biome BiomeDesert(2.0f, 0.0f); +static const Biome BiomeMountains(0.2f, 0.3f); +static const Biome BiomeForest(0.7f, 0.8f); +static const Biome BiomeTaiga(0.25f, 0.8f); +static const SwampBiome BiomeSwamp(0.8f, 0.9f, {0.380f, 0.482f, 0.392f}); +static const Biome BiomeFrozen(0.0f, 0.5f); +static const Biome BiomeMushroomFields(0.9f, 1.0f); +static const Biome BiomeJungle(0.95f, 0.9f); +static const Biome BiomeJungleEdge(0.95f, 0.8f); +static const Biome BiomeSnowyBeach(0.05f, 0.3f); +static const Biome BiomeBirchForest(0.6f, 0.6f); +static const DarkForestBiome BiomeDarkForest(0.7f, 0.8f); +static const Biome BiomeSnowyTaiga(-0.5f, 0.4f); +static const Biome BiomeGiantTreeTaiga(0.3f, 0.8f); +static const Biome BiomeSavanna(1.2f, 0.0f); +static const Biome BiomeSavannaPlateau(1.0f, 0.0f); +static const Biome BiomeShatteredSavanna(1.1f, 0.0f); +static const BadlandsBiome BiomeBadlands(2.0f, 0.0f); + +static const Biome BiomeFrozenOcean(0.0f, 0.5f, {0.224f, 0.220f, 0.788f}); +static const Biome BiomeWarmOcean(0.8f, 0.5f, {0.263f, 0.835f, 0.933f}); +static const Biome BiomeLukewarmOcean(0.8f, 0.5f, {0.271f, 0.678f, 0.949f}); +static const Biome BiomeColdOcean(0.8f, 0.5f, {0.239f, 0.341f, 0.839f}); + +extern const Biome *const BIOME_DEFAULT = &BiomeDefault; + +const Biome *const BIOMES[256] = { + /* 0 */ &BiomeDefault, /* Ocean */ + /* 1 */ &BiomePlains, + /* 2 */ &BiomeDesert, + /* 3 */ &BiomeMountains, + /* 4 */ &BiomeForest, + /* 5 */ &BiomeTaiga, + /* 6 */ &BiomeSwamp, + /* 7 */ &BiomeDefault, /* River */ + /* 8 */ &BiomeDesert, /* Nether */ + /* 9 */ &BiomeDefault, /* The End */ + /* 10 */ &BiomeFrozenOcean, + /* 11 */ &BiomeFrozenOcean, /* Frozen River */ + /* 12 */ &BiomeFrozen, /* Snowy Tundra */ + /* 13 */ &BiomeFrozen, /* Snowy Mountains */ + /* 14 */ &BiomeMushroomFields, + /* 15 */ &BiomeMushroomFields, /* Mushroom Field Shore */ + /* 16 */ &BiomePlains, /* Beach */ + /* 17 */ &BiomeDesert, /* Desert Hills */ + /* 18 */ &BiomeForest, /* Wooded Hiils */ + /* 19 */ &BiomeTaiga, /* Taiga Hills */ + /* 20 */ &BiomeMountains, /* Moutain Edge */ + /* 21 */ &BiomeJungle, + /* 22 */ &BiomeJungle, /* Jungle Hills */ + /* 23 */ &BiomeJungleEdge, + /* 24 */ &BiomeDefault, /* Deep Ocean */ + /* 25 */ &BiomeMountains, /* Stone Shore */ + /* 26 */ &BiomeSnowyBeach, + /* 27 */ &BiomeBirchForest, + /* 28 */ &BiomeBirchForest, /* Birch Forest Hills */ + /* 29 */ &BiomeDarkForest, + /* 30 */ &BiomeSnowyTaiga, + /* 31 */ &BiomeSnowyTaiga, /* Snowy Taiga Hills */ + /* 32 */ &BiomeGiantTreeTaiga, + /* 33 */ &BiomeGiantTreeTaiga, /* Giant Tree Taiga Hills */ + /* 34 */ &BiomeMountains, /* Wooded Mountains */ + /* 35 */ &BiomeSavanna, + /* 36 */ &BiomeSavanna, /* Savanna Plateau */ + /* 37 */ &BiomeBadlands, + /* 38 */ &BiomeBadlands, /* Wooded Badlands Plateau */ + /* 39 */ &BiomeBadlands, /* Badlands Plateau */ + /* 40 */ &BiomeDefault, /* Small End Islands */ + /* 41 */ &BiomeDefault, /* End Midlands */ + /* 42 */ &BiomeDefault, /* End Highlands */ + /* 43 */ &BiomeDefault, /* End Barrens */ + /* 44 */ &BiomeWarmOcean, + /* 45 */ &BiomeLukewarmOcean, + /* 46 */ &BiomeColdOcean, + /* 47 */ &BiomeWarmOcean, /* Deep Warm Ocean */ + /* 48 */ &BiomeLukewarmOcean, /* Deep Lukewarm Ocean */ + /* 49 */ &BiomeColdOcean, /* Deep Cold Ocean */ + /* 50 */ &BiomeFrozenOcean, /* Deep Frozen Ocean */ + /* 51 */ nullptr, + /* 52 */ nullptr, + /* 53 */ nullptr, + /* 54 */ nullptr, + /* 55 */ nullptr, + /* 56 */ nullptr, + /* 57 */ nullptr, + /* 58 */ nullptr, + /* 59 */ nullptr, + /* 60 */ nullptr, + /* 61 */ nullptr, + /* 62 */ nullptr, + /* 63 */ nullptr, + /* 64 */ nullptr, + /* 65 */ nullptr, + /* 66 */ nullptr, + /* 67 */ nullptr, + /* 68 */ nullptr, + /* 69 */ nullptr, + /* 70 */ nullptr, + /* 71 */ nullptr, + /* 72 */ nullptr, + /* 73 */ nullptr, + /* 74 */ nullptr, + /* 75 */ nullptr, + /* 76 */ nullptr, + /* 77 */ nullptr, + /* 78 */ nullptr, + /* 79 */ nullptr, + /* 80 */ nullptr, + /* 81 */ nullptr, + /* 82 */ nullptr, + /* 83 */ nullptr, + /* 84 */ nullptr, + /* 85 */ nullptr, + /* 86 */ nullptr, + /* 87 */ nullptr, + /* 88 */ nullptr, + /* 89 */ nullptr, + /* 90 */ nullptr, + /* 91 */ nullptr, + /* 92 */ nullptr, + /* 93 */ nullptr, + /* 94 */ nullptr, + /* 95 */ nullptr, + /* 96 */ nullptr, + /* 97 */ nullptr, + /* 98 */ nullptr, + /* 99 */ nullptr, + /* 100 */ nullptr, + /* 101 */ nullptr, + /* 102 */ nullptr, + /* 103 */ nullptr, + /* 104 */ nullptr, + /* 105 */ nullptr, + /* 106 */ nullptr, + /* 107 */ nullptr, + /* 108 */ nullptr, + /* 109 */ nullptr, + /* 110 */ nullptr, + /* 111 */ nullptr, + /* 112 */ nullptr, + /* 113 */ nullptr, + /* 114 */ nullptr, + /* 115 */ nullptr, + /* 116 */ nullptr, + /* 117 */ nullptr, + /* 118 */ nullptr, + /* 119 */ nullptr, + /* 120 */ nullptr, + /* 121 */ nullptr, + /* 122 */ nullptr, + /* 123 */ nullptr, + /* 124 */ nullptr, + /* 125 */ nullptr, + /* 126 */ nullptr, + /* 127 */ &BiomeDefault, /* The Void */ + /* 128 */ nullptr, + /* 129 */ &BiomeDefault, /* Sunflower Plains */ + /* 130 */ &BiomeDesert, /* Desert Lakes */ + /* 131 */ &BiomeMountains, /* Gravelly Mountains */ + /* 132 */ &BiomeForest, /* Flower Forest */ + /* 133 */ &BiomeTaiga, /* Taiga Mountains */ + /* 134 */ &BiomeSwamp, /* Swamp Hills */ + /* 135 */ nullptr, + /* 136 */ nullptr, + /* 137 */ nullptr, + /* 138 */ nullptr, + /* 139 */ nullptr, + /* 140 */ &BiomeFrozen, /* Ice Spikes */ + /* 141 */ nullptr, + /* 142 */ nullptr, + /* 143 */ nullptr, + /* 144 */ nullptr, + /* 145 */ nullptr, + /* 146 */ nullptr, + /* 147 */ nullptr, + /* 148 */ nullptr, + /* 149 */ &BiomeJungle, /* Modified Jungle */ + /* 150 */ nullptr, + /* 151 */ &BiomeJungleEdge, /* Modified Jungle Edge */ + /* 152 */ nullptr, + /* 153 */ nullptr, + /* 154 */ nullptr, + /* 155 */ &BiomeBirchForest, /* Tall Birch Forest */ + /* 156 */ &BiomeBirchForest, /* Tall Birch Hills */ + /* 157 */ &BiomeDarkForest, /* Dark Forest Hills */ + /* 158 */ &BiomeSnowyTaiga, /* Snowy Taiga Mountains */ + /* 159 */ nullptr, + /* 160 */ &BiomeTaiga, /* Giant Spruce Taiga */ + /* 161 */ &BiomeTaiga, /* Giant Spruce Taiga Hills */ + /* 162 */ &BiomeMountains, /* Gravelly Mountains+ */ + /* 163 */ &BiomeShatteredSavanna, + /* 164 */ &BiomeSavannaPlateau, /* Shattered Savanna Plateau */ + /* 165 */ &BiomeBadlands, /* Eroded Badlands */ + /* 166 */ &BiomeBadlands, /* Modified Wooded Badlands Plateau */ + /* 167 */ &BiomeBadlands, /* Modified Badlands Plateau */ + /* 168 */ &BiomeJungle, /* Bamboo Jungle */ + /* 169 */ &BiomeJungle, /* Bamboo Jungle Hills */ + /* 170 */ &BiomeDesert, /* Soul Sand Valley */ + /* 171 */ &BiomeDesert, /* Crimson Forest */ + /* 172 */ &BiomeDesert, /* Warped Forest */ + /* 173 */ &BiomeDesert, /* Basalt Deltas */ +}; + +} +} diff --git a/src/Resource/Biome.hpp b/src/Resource/Biome.hpp new file mode 100644 index 0000000..e094f17 --- /dev/null +++ b/src/Resource/Biome.hpp @@ -0,0 +1,59 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Color.hpp" + + +namespace MinedMap { +namespace Resource { + +class BlockType; + +class Biome { +private: + float temp, rain; + FloatColor water; + +protected: + virtual FloatColor getGrassColor(float temp, float rain) const; + virtual FloatColor getFoliageColor(float temp, float rain) const; + + FloatColor getWaterColor() const { return water; }; + +public: + Biome(float temp0, float rain0, FloatColor water0 = {0.247f, 0.463f, 0.894f}) + : temp(temp0), rain(rain0), water(water0) {} + + FloatColor getBlockColor(const BlockType *type, unsigned height) const; +}; + +extern const Biome *const BIOME_DEFAULT; +extern const Biome *const BIOMES[256]; + +} +} diff --git a/src/Resource/BlockType.cpp b/src/Resource/BlockType.cpp new file mode 100644 index 0000000..e72456e --- /dev/null +++ b/src/Resource/BlockType.cpp @@ -0,0 +1,87 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "BlockType.hpp" + + +namespace MinedMap { +namespace Resource { + +const std::unordered_map BlockType::Types = { + +#include "BlockType.inc" + +}; + +struct LegacyBlockType { + const char *data[16]; +}; + +static constexpr LegacyBlockType simple(const char *t) { + return { + t, t, t, t, + t, t, t, t, + t, t, t, t, + t, t, t, t, + }; +} + +static const LegacyBlockType LEGACY_BLOCK_TYPE_DATA[256] = { + +#include "LegacyBlockType.inc" + +}; + + +const BlockType * BlockType::lookup(const std::string &name) { + auto it = Types.find(name); + if (it == Types.end()) + return nullptr; + + return &it->second; +} + +static LegacyPalette makeLegacyPalette() { + const std::string name_prefix("minecraft:"); + + LegacyPalette palette = {}; + for (size_t type = 0; type < 256; type++) { + for (size_t data = 0; data < 16; data++) { + const char *name = LEGACY_BLOCK_TYPE_DATA[type].data[data]; + if (!name) + continue; + + palette.types[type][data] = BlockType::lookup(name_prefix + name); + } + } + + return palette; +} + +const LegacyPalette LEGACY_BLOCK_TYPES = makeLegacyPalette(); + +} +} diff --git a/src/Resource/BlockType.hpp b/src/Resource/BlockType.hpp new file mode 100644 index 0000000..24a46c3 --- /dev/null +++ b/src/Resource/BlockType.hpp @@ -0,0 +1,64 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include +#include + +namespace MinedMap { +namespace Resource { + +#define BLOCK_OPAQUE (1u << 0) +#define BLOCK_GRASS (1u << 1) +#define BLOCK_FOLIAGE (1u << 2) +#define BLOCK_BIRCH (1u << 3) +#define BLOCK_SPRUCE (1u << 4) +#define BLOCK_WATER (1u << 5) + +struct BlockType { +private: + static const std::unordered_map Types; + +public: + static const BlockType * lookup(const std::string &name); + + uint8_t flags; + struct { + uint8_t r, g, b; + } color; +}; + + +struct LegacyPalette { + const BlockType *types[256][16]; +}; + +extern const LegacyPalette LEGACY_BLOCK_TYPES; + +} +} diff --git a/src/Resource/BlockType.inc b/src/Resource/BlockType.inc new file mode 100644 index 0000000..a76fa7a --- /dev/null +++ b/src/Resource/BlockType.inc @@ -0,0 +1,766 @@ +{"minecraft:acacia_button", {0, {0, 0, 0}}}, +{"minecraft:acacia_door", {BLOCK_OPAQUE, {167, 95, 60}}}, +{"minecraft:acacia_fence", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_fence_gate", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_leaves", {BLOCK_OPAQUE|BLOCK_FOLIAGE, {149, 148, 148}}}, +{"minecraft:acacia_log", {BLOCK_OPAQUE, {150, 88, 55}}}, +{"minecraft:acacia_planks", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_pressure_plate", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_sapling", {BLOCK_OPAQUE, {118, 117, 23}}}, +{"minecraft:acacia_sign", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_slab", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_stairs", {BLOCK_OPAQUE, {168, 90, 50}}}, +{"minecraft:acacia_trapdoor", {BLOCK_OPAQUE, {156, 87, 51}}}, +{"minecraft:acacia_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:acacia_wood", {BLOCK_OPAQUE, {103, 96, 86}}}, +{"minecraft:activator_rail", {BLOCK_OPAQUE, {115, 87, 74}}}, +{"minecraft:air", {0, {0, 0, 0}}}, +{"minecraft:allium", {0, {0, 0, 0}}}, +{"minecraft:ancient_debris", {BLOCK_OPAQUE, {94, 66, 58}}}, +{"minecraft:andesite", {BLOCK_OPAQUE, {136, 136, 136}}}, +{"minecraft:andesite_slab", {BLOCK_OPAQUE, {136, 136, 136}}}, +{"minecraft:andesite_stairs", {BLOCK_OPAQUE, {136, 136, 136}}}, +{"minecraft:andesite_wall", {BLOCK_OPAQUE, {136, 136, 136}}}, +{"minecraft:anvil", {BLOCK_OPAQUE, {72, 72, 72}}}, +{"minecraft:attached_melon_stem", {BLOCK_OPAQUE|BLOCK_GRASS, {141, 142, 141}}}, +{"minecraft:attached_pumpkin_stem", {BLOCK_OPAQUE|BLOCK_GRASS, {139, 139, 139}}}, +{"minecraft:azure_bluet", {0, {0, 0, 0}}}, +{"minecraft:bamboo", {BLOCK_OPAQUE, {93, 144, 19}}}, +{"minecraft:bamboo_sapling", {0, {0, 0, 0}}}, +{"minecraft:barrel", {BLOCK_OPAQUE, {134, 100, 58}}}, +{"minecraft:barrier", {0, {0, 0, 0}}}, +{"minecraft:basalt", {BLOCK_OPAQUE, {80, 81, 86}}}, +{"minecraft:beacon", {BLOCK_OPAQUE, {117, 220, 215}}}, +{"minecraft:bedrock", {BLOCK_OPAQUE, {85, 85, 85}}}, +{"minecraft:bee_nest", {BLOCK_OPAQUE, {202, 160, 74}}}, +{"minecraft:beehive", {BLOCK_OPAQUE, {180, 146, 90}}}, +{"minecraft:beetroots", {BLOCK_OPAQUE, {93, 91, 30}}}, +{"minecraft:bell", {BLOCK_OPAQUE, {253, 235, 110}}}, +{"minecraft:birch_button", {0, {0, 0, 0}}}, +{"minecraft:birch_door", {BLOCK_OPAQUE, {220, 209, 176}}}, +{"minecraft:birch_fence", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_fence_gate", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_leaves", {BLOCK_OPAQUE|BLOCK_BIRCH, {130, 129, 130}}}, +{"minecraft:birch_log", {BLOCK_OPAQUE, {193, 179, 135}}}, +{"minecraft:birch_planks", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_pressure_plate", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_sapling", {BLOCK_OPAQUE, {127, 160, 79}}}, +{"minecraft:birch_sign", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_slab", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_stairs", {BLOCK_OPAQUE, {192, 175, 121}}}, +{"minecraft:birch_trapdoor", {BLOCK_OPAQUE, {207, 194, 157}}}, +{"minecraft:birch_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:birch_wood", {BLOCK_OPAQUE, {216, 215, 210}}}, +{"minecraft:black_banner", {0, {0, 0, 0}}}, +{"minecraft:black_bed", {0, {0, 0, 0}}}, +{"minecraft:black_carpet", {BLOCK_OPAQUE, {20, 21, 25}}}, +{"minecraft:black_concrete", {BLOCK_OPAQUE, {8, 10, 15}}}, +{"minecraft:black_concrete_powder", {BLOCK_OPAQUE, {25, 26, 31}}}, +{"minecraft:black_glazed_terracotta", {BLOCK_OPAQUE, {67, 30, 32}}}, +{"minecraft:black_shulker_box", {BLOCK_OPAQUE, {25, 25, 29}}}, +{"minecraft:black_stained_glass", {BLOCK_OPAQUE, {25, 25, 25}}}, +{"minecraft:black_stained_glass_pane", {BLOCK_OPAQUE, {24, 24, 24}}}, +{"minecraft:black_terracotta", {BLOCK_OPAQUE, {37, 22, 16}}}, +{"minecraft:black_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:black_wool", {BLOCK_OPAQUE, {20, 21, 25}}}, +{"minecraft:blackstone", {BLOCK_OPAQUE, {42, 36, 41}}}, +{"minecraft:blackstone_slab", {BLOCK_OPAQUE, {42, 36, 41}}}, +{"minecraft:blackstone_stairs", {BLOCK_OPAQUE, {42, 36, 41}}}, +{"minecraft:blackstone_wall", {BLOCK_OPAQUE, {42, 36, 41}}}, +{"minecraft:blast_furnace", {BLOCK_OPAQUE, {80, 80, 81}}}, +{"minecraft:blue_banner", {0, {0, 0, 0}}}, +{"minecraft:blue_bed", {0, {0, 0, 0}}}, +{"minecraft:blue_carpet", {BLOCK_OPAQUE, {53, 57, 157}}}, +{"minecraft:blue_concrete", {BLOCK_OPAQUE, {44, 46, 143}}}, +{"minecraft:blue_concrete_powder", {BLOCK_OPAQUE, {70, 73, 166}}}, +{"minecraft:blue_glazed_terracotta", {BLOCK_OPAQUE, {47, 64, 139}}}, +{"minecraft:blue_ice", {BLOCK_OPAQUE, {116, 167, 253}}}, +{"minecraft:blue_orchid", {0, {0, 0, 0}}}, +{"minecraft:blue_shulker_box", {BLOCK_OPAQUE, {43, 45, 140}}}, +{"minecraft:blue_stained_glass", {BLOCK_OPAQUE, {51, 76, 178}}}, +{"minecraft:blue_stained_glass_pane", {BLOCK_OPAQUE, {48, 73, 171}}}, +{"minecraft:blue_terracotta", {BLOCK_OPAQUE, {74, 59, 91}}}, +{"minecraft:blue_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:blue_wool", {BLOCK_OPAQUE, {53, 57, 157}}}, +{"minecraft:bone_block", {BLOCK_OPAQUE, {209, 206, 179}}}, +{"minecraft:bookshelf", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:brain_coral", {0, {0, 0, 0}}}, +{"minecraft:brain_coral_block", {BLOCK_OPAQUE, {207, 91, 159}}}, +{"minecraft:brain_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:brain_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:brewing_stand", {BLOCK_OPAQUE, {123, 101, 81}}}, +{"minecraft:brick_slab", {BLOCK_OPAQUE, {150, 97, 83}}}, +{"minecraft:brick_stairs", {BLOCK_OPAQUE, {150, 97, 83}}}, +{"minecraft:brick_wall", {BLOCK_OPAQUE, {150, 97, 83}}}, +{"minecraft:bricks", {BLOCK_OPAQUE, {150, 97, 83}}}, +{"minecraft:brown_banner", {0, {0, 0, 0}}}, +{"minecraft:brown_bed", {0, {0, 0, 0}}}, +{"minecraft:brown_carpet", {BLOCK_OPAQUE, {114, 71, 40}}}, +{"minecraft:brown_concrete", {BLOCK_OPAQUE, {96, 59, 31}}}, +{"minecraft:brown_concrete_powder", {BLOCK_OPAQUE, {125, 84, 53}}}, +{"minecraft:brown_glazed_terracotta", {BLOCK_OPAQUE, {119, 106, 85}}}, +{"minecraft:brown_mushroom", {0, {0, 0, 0}}}, +{"minecraft:brown_mushroom_block", {BLOCK_OPAQUE, {149, 111, 81}}}, +{"minecraft:brown_shulker_box", {BLOCK_OPAQUE, {106, 66, 35}}}, +{"minecraft:brown_stained_glass", {BLOCK_OPAQUE, {102, 76, 51}}}, +{"minecraft:brown_stained_glass_pane", {BLOCK_OPAQUE, {97, 73, 48}}}, +{"minecraft:brown_terracotta", {BLOCK_OPAQUE, {77, 51, 35}}}, +{"minecraft:brown_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:brown_wool", {BLOCK_OPAQUE, {114, 71, 40}}}, +{"minecraft:bubble_column", {BLOCK_OPAQUE|BLOCK_WATER, {177, 177, 177}}}, +{"minecraft:bubble_coral", {0, {0, 0, 0}}}, +{"minecraft:bubble_coral_block", {BLOCK_OPAQUE, {165, 26, 162}}}, +{"minecraft:bubble_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:bubble_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:cactus", {BLOCK_OPAQUE, {85, 127, 43}}}, +{"minecraft:cake", {BLOCK_OPAQUE, {248, 222, 214}}}, +{"minecraft:campfire", {BLOCK_OPAQUE, {110, 88, 54}}}, +{"minecraft:carrots", {BLOCK_OPAQUE, {81, 123, 37}}}, +{"minecraft:cartography_table", {BLOCK_OPAQUE, {104, 87, 67}}}, +{"minecraft:carved_pumpkin", {BLOCK_OPAQUE, {198, 118, 24}}}, +{"minecraft:cauldron", {BLOCK_OPAQUE, {73, 72, 74}}}, +{"minecraft:cave_air", {0, {0, 0, 0}}}, +{"minecraft:chain", {0, {0, 0, 0}}}, +{"minecraft:chain_command_block", {BLOCK_OPAQUE, {131, 161, 147}}}, +{"minecraft:chest", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:chipped_anvil", {BLOCK_OPAQUE, {72, 72, 72}}}, +{"minecraft:chiseled_nether_bricks", {BLOCK_OPAQUE, {47, 23, 28}}}, +{"minecraft:chiseled_polished_blackstone", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:chiseled_quartz_block", {BLOCK_OPAQUE, {231, 226, 218}}}, +{"minecraft:chiseled_red_sandstone", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:chiseled_sandstone", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:chiseled_stone_bricks", {BLOCK_OPAQUE, {119, 118, 119}}}, +{"minecraft:chorus_flower", {BLOCK_OPAQUE, {151, 120, 151}}}, +{"minecraft:chorus_plant", {BLOCK_OPAQUE, {93, 57, 93}}}, +{"minecraft:clay", {BLOCK_OPAQUE, {160, 166, 179}}}, +{"minecraft:coal_block", {BLOCK_OPAQUE, {16, 15, 15}}}, +{"minecraft:coal_ore", {BLOCK_OPAQUE, {116, 116, 116}}}, +{"minecraft:coarse_dirt", {BLOCK_OPAQUE, {119, 85, 59}}}, +{"minecraft:cobblestone", {BLOCK_OPAQUE, {127, 127, 127}}}, +{"minecraft:cobblestone_slab", {BLOCK_OPAQUE, {127, 127, 127}}}, +{"minecraft:cobblestone_stairs", {BLOCK_OPAQUE, {127, 127, 127}}}, +{"minecraft:cobblestone_wall", {BLOCK_OPAQUE, {127, 127, 127}}}, +{"minecraft:cobweb", {BLOCK_OPAQUE, {228, 233, 234}}}, +{"minecraft:cocoa", {BLOCK_OPAQUE, {156, 94, 43}}}, +{"minecraft:command_block", {BLOCK_OPAQUE, {181, 136, 108}}}, +{"minecraft:comparator", {BLOCK_OPAQUE, {166, 161, 159}}}, +{"minecraft:composter", {BLOCK_OPAQUE, {88, 61, 23}}}, +{"minecraft:conduit", {BLOCK_OPAQUE, {159, 139, 113}}}, +{"minecraft:cornflower", {0, {0, 0, 0}}}, +{"minecraft:cracked_nether_bricks", {BLOCK_OPAQUE, {40, 20, 23}}}, +{"minecraft:cracked_polished_blackstone_bricks", {BLOCK_OPAQUE, {43, 37, 43}}}, +{"minecraft:cracked_stone_bricks", {BLOCK_OPAQUE, {118, 117, 118}}}, +{"minecraft:crafting_table", {BLOCK_OPAQUE, {119, 73, 42}}}, +{"minecraft:creeper_head", {0, {0, 0, 0}}}, +{"minecraft:creeper_wall_head", {0, {0, 0, 0}}}, +{"minecraft:crimson_button", {0, {0, 0, 0}}}, +{"minecraft:crimson_door", {BLOCK_OPAQUE, {114, 54, 79}}}, +{"minecraft:crimson_fence", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_fence_gate", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_fungus", {0, {0, 0, 0}}}, +{"minecraft:crimson_hyphae", {BLOCK_OPAQUE, {92, 25, 29}}}, +{"minecraft:crimson_nylium", {BLOCK_OPAQUE, {130, 31, 31}}}, +{"minecraft:crimson_planks", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_pressure_plate", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_roots", {BLOCK_OPAQUE, {126, 8, 41}}}, +{"minecraft:crimson_sign", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_slab", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_stairs", {BLOCK_OPAQUE, {101, 48, 70}}}, +{"minecraft:crimson_stem", {BLOCK_OPAQUE, {107, 51, 74}}}, +{"minecraft:crimson_trapdoor", {BLOCK_OPAQUE, {103, 50, 72}}}, +{"minecraft:crimson_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:crying_obsidian", {BLOCK_OPAQUE, {32, 10, 60}}}, +{"minecraft:cut_red_sandstone", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:cut_red_sandstone_slab", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:cut_sandstone", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:cut_sandstone_slab", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:cyan_banner", {0, {0, 0, 0}}}, +{"minecraft:cyan_bed", {0, {0, 0, 0}}}, +{"minecraft:cyan_carpet", {BLOCK_OPAQUE, {21, 137, 145}}}, +{"minecraft:cyan_concrete", {BLOCK_OPAQUE, {21, 119, 136}}}, +{"minecraft:cyan_concrete_powder", {BLOCK_OPAQUE, {36, 147, 157}}}, +{"minecraft:cyan_glazed_terracotta", {BLOCK_OPAQUE, {52, 118, 125}}}, +{"minecraft:cyan_shulker_box", {BLOCK_OPAQUE, {20, 121, 135}}}, +{"minecraft:cyan_stained_glass", {BLOCK_OPAQUE, {76, 127, 153}}}, +{"minecraft:cyan_stained_glass_pane", {BLOCK_OPAQUE, {73, 122, 147}}}, +{"minecraft:cyan_terracotta", {BLOCK_OPAQUE, {86, 91, 91}}}, +{"minecraft:cyan_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:cyan_wool", {BLOCK_OPAQUE, {21, 137, 145}}}, +{"minecraft:damaged_anvil", {BLOCK_OPAQUE, {72, 72, 72}}}, +{"minecraft:dandelion", {0, {0, 0, 0}}}, +{"minecraft:dark_oak_button", {0, {0, 0, 0}}}, +{"minecraft:dark_oak_door", {BLOCK_OPAQUE, {76, 51, 25}}}, +{"minecraft:dark_oak_fence", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_fence_gate", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_leaves", {BLOCK_OPAQUE|BLOCK_FOLIAGE, {150, 150, 150}}}, +{"minecraft:dark_oak_log", {BLOCK_OPAQUE, {64, 42, 21}}}, +{"minecraft:dark_oak_planks", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_pressure_plate", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_sapling", {BLOCK_OPAQUE, {61, 90, 30}}}, +{"minecraft:dark_oak_sign", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_slab", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_stairs", {BLOCK_OPAQUE, {66, 43, 20}}}, +{"minecraft:dark_oak_trapdoor", {BLOCK_OPAQUE, {75, 49, 23}}}, +{"minecraft:dark_oak_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:dark_oak_wood", {BLOCK_OPAQUE, {60, 46, 26}}}, +{"minecraft:dark_prismarine", {BLOCK_OPAQUE, {51, 91, 75}}}, +{"minecraft:dark_prismarine_slab", {BLOCK_OPAQUE, {51, 91, 75}}}, +{"minecraft:dark_prismarine_stairs", {BLOCK_OPAQUE, {51, 91, 75}}}, +{"minecraft:daylight_detector", {BLOCK_OPAQUE, {130, 116, 94}}}, +{"minecraft:dead_brain_coral", {0, {0, 0, 0}}}, +{"minecraft:dead_brain_coral_block", {BLOCK_OPAQUE, {124, 117, 114}}}, +{"minecraft:dead_brain_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_brain_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_bubble_coral", {0, {0, 0, 0}}}, +{"minecraft:dead_bubble_coral_block", {BLOCK_OPAQUE, {131, 123, 119}}}, +{"minecraft:dead_bubble_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_bubble_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_bush", {BLOCK_OPAQUE, {107, 78, 40}}}, +{"minecraft:dead_fire_coral", {0, {0, 0, 0}}}, +{"minecraft:dead_fire_coral_block", {BLOCK_OPAQUE, {131, 123, 119}}}, +{"minecraft:dead_fire_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_fire_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_horn_coral", {0, {0, 0, 0}}}, +{"minecraft:dead_horn_coral_block", {BLOCK_OPAQUE, {133, 126, 122}}}, +{"minecraft:dead_horn_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_horn_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_tube_coral", {0, {0, 0, 0}}}, +{"minecraft:dead_tube_coral_block", {BLOCK_OPAQUE, {130, 123, 119}}}, +{"minecraft:dead_tube_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:dead_tube_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:detector_rail", {BLOCK_OPAQUE, {123, 104, 90}}}, +{"minecraft:diamond_block", {BLOCK_OPAQUE, {98, 237, 228}}}, +{"minecraft:diamond_ore", {BLOCK_OPAQUE, {125, 142, 141}}}, +{"minecraft:diorite", {BLOCK_OPAQUE, {188, 188, 188}}}, +{"minecraft:diorite_slab", {BLOCK_OPAQUE, {188, 188, 188}}}, +{"minecraft:diorite_stairs", {BLOCK_OPAQUE, {188, 188, 188}}}, +{"minecraft:diorite_wall", {BLOCK_OPAQUE, {188, 188, 188}}}, +{"minecraft:dirt", {BLOCK_OPAQUE, {134, 96, 67}}}, +{"minecraft:dispenser", {BLOCK_OPAQUE, {110, 109, 109}}}, +{"minecraft:dragon_egg", {BLOCK_OPAQUE, {12, 9, 15}}}, +{"minecraft:dragon_head", {0, {0, 0, 0}}}, +{"minecraft:dragon_wall_head", {0, {0, 0, 0}}}, +{"minecraft:dried_kelp_block", {BLOCK_OPAQUE, {50, 58, 38}}}, +{"minecraft:dropper", {BLOCK_OPAQUE, {110, 109, 109}}}, +{"minecraft:emerald_block", {BLOCK_OPAQUE, {42, 203, 87}}}, +{"minecraft:emerald_ore", {BLOCK_OPAQUE, {117, 136, 124}}}, +{"minecraft:enchanting_table", {BLOCK_OPAQUE, {128, 75, 85}}}, +{"minecraft:end_gateway", {BLOCK_OPAQUE, {15, 10, 24}}}, +{"minecraft:end_portal", {BLOCK_OPAQUE, {15, 10, 24}}}, +{"minecraft:end_portal_frame", {BLOCK_OPAQUE, {91, 120, 97}}}, +{"minecraft:end_rod", {0, {0, 0, 0}}}, +{"minecraft:end_stone", {BLOCK_OPAQUE, {219, 222, 158}}}, +{"minecraft:end_stone_brick_slab", {BLOCK_OPAQUE, {218, 224, 162}}}, +{"minecraft:end_stone_brick_stairs", {BLOCK_OPAQUE, {218, 224, 162}}}, +{"minecraft:end_stone_brick_wall", {BLOCK_OPAQUE, {218, 224, 162}}}, +{"minecraft:end_stone_bricks", {BLOCK_OPAQUE, {218, 224, 162}}}, +{"minecraft:ender_chest", {BLOCK_OPAQUE, {15, 10, 24}}}, +{"minecraft:farmland", {BLOCK_OPAQUE, {81, 44, 15}}}, +{"minecraft:fern", {0, {0, 0, 0}}}, +{"minecraft:fire", {BLOCK_OPAQUE, {211, 140, 53}}}, +{"minecraft:fire_coral", {0, {0, 0, 0}}}, +{"minecraft:fire_coral_block", {BLOCK_OPAQUE, {163, 35, 46}}}, +{"minecraft:fire_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:fire_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:fletching_table", {BLOCK_OPAQUE, {197, 180, 133}}}, +{"minecraft:flower_pot", {BLOCK_OPAQUE, {124, 68, 53}}}, +{"minecraft:frosted_ice", {BLOCK_OPAQUE, {140, 181, 252}}}, +{"minecraft:furnace", {BLOCK_OPAQUE, {110, 109, 109}}}, +{"minecraft:gilded_blackstone", {BLOCK_OPAQUE, {56, 43, 38}}}, +{"minecraft:glass", {BLOCK_OPAQUE, {175, 213, 219}}}, +{"minecraft:glass_pane", {BLOCK_OPAQUE, {211, 239, 244}}}, +{"minecraft:glowstone", {BLOCK_OPAQUE, {171, 131, 84}}}, +{"minecraft:gold_block", {BLOCK_OPAQUE, {246, 208, 61}}}, +{"minecraft:gold_ore", {BLOCK_OPAQUE, {143, 140, 125}}}, +{"minecraft:granite", {BLOCK_OPAQUE, {149, 103, 85}}}, +{"minecraft:granite_slab", {BLOCK_OPAQUE, {149, 103, 85}}}, +{"minecraft:granite_stairs", {BLOCK_OPAQUE, {149, 103, 85}}}, +{"minecraft:granite_wall", {BLOCK_OPAQUE, {149, 103, 85}}}, +{"minecraft:grass", {0, {0, 0, 0}}}, +{"minecraft:grass_block", {BLOCK_OPAQUE|BLOCK_GRASS, {147, 147, 147}}}, +{"minecraft:grass_path", {BLOCK_OPAQUE, {148, 121, 65}}}, +{"minecraft:gravel", {BLOCK_OPAQUE, {131, 127, 126}}}, +{"minecraft:gray_banner", {0, {0, 0, 0}}}, +{"minecraft:gray_bed", {0, {0, 0, 0}}}, +{"minecraft:gray_carpet", {BLOCK_OPAQUE, {62, 68, 71}}}, +{"minecraft:gray_concrete", {BLOCK_OPAQUE, {54, 57, 61}}}, +{"minecraft:gray_concrete_powder", {BLOCK_OPAQUE, {76, 81, 84}}}, +{"minecraft:gray_glazed_terracotta", {BLOCK_OPAQUE, {83, 90, 93}}}, +{"minecraft:gray_shulker_box", {BLOCK_OPAQUE, {55, 58, 62}}}, +{"minecraft:gray_stained_glass", {BLOCK_OPAQUE, {76, 76, 76}}}, +{"minecraft:gray_stained_glass_pane", {BLOCK_OPAQUE, {73, 73, 73}}}, +{"minecraft:gray_terracotta", {BLOCK_OPAQUE, {57, 42, 35}}}, +{"minecraft:gray_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:gray_wool", {BLOCK_OPAQUE, {62, 68, 71}}}, +{"minecraft:green_banner", {0, {0, 0, 0}}}, +{"minecraft:green_bed", {0, {0, 0, 0}}}, +{"minecraft:green_carpet", {BLOCK_OPAQUE, {84, 109, 27}}}, +{"minecraft:green_concrete", {BLOCK_OPAQUE, {73, 91, 36}}}, +{"minecraft:green_concrete_powder", {BLOCK_OPAQUE, {97, 119, 44}}}, +{"minecraft:green_glazed_terracotta", {BLOCK_OPAQUE, {117, 142, 67}}}, +{"minecraft:green_shulker_box", {BLOCK_OPAQUE, {79, 100, 31}}}, +{"minecraft:green_stained_glass", {BLOCK_OPAQUE, {102, 127, 51}}}, +{"minecraft:green_stained_glass_pane", {BLOCK_OPAQUE, {97, 122, 48}}}, +{"minecraft:green_terracotta", {BLOCK_OPAQUE, {76, 83, 42}}}, +{"minecraft:green_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:green_wool", {BLOCK_OPAQUE, {84, 109, 27}}}, +{"minecraft:grindstone", {BLOCK_OPAQUE, {142, 142, 142}}}, +{"minecraft:hay_block", {BLOCK_OPAQUE, {165, 139, 12}}}, +{"minecraft:heavy_weighted_pressure_plate", {BLOCK_OPAQUE, {220, 220, 220}}}, +{"minecraft:honey_block", {BLOCK_OPAQUE, {251, 185, 52}}}, +{"minecraft:honeycomb_block", {BLOCK_OPAQUE, {229, 148, 29}}}, +{"minecraft:hopper", {BLOCK_OPAQUE, {75, 74, 75}}}, +{"minecraft:horn_coral", {0, {0, 0, 0}}}, +{"minecraft:horn_coral_block", {BLOCK_OPAQUE, {216, 199, 66}}}, +{"minecraft:horn_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:horn_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:ice", {BLOCK_OPAQUE, {145, 183, 253}}}, +{"minecraft:infested_chiseled_stone_bricks", {BLOCK_OPAQUE, {119, 118, 119}}}, +{"minecraft:infested_cobblestone", {BLOCK_OPAQUE, {127, 127, 127}}}, +{"minecraft:infested_cracked_stone_bricks", {BLOCK_OPAQUE, {118, 117, 118}}}, +{"minecraft:infested_mossy_stone_bricks", {BLOCK_OPAQUE, {115, 121, 105}}}, +{"minecraft:infested_stone", {BLOCK_OPAQUE, {125, 125, 125}}}, +{"minecraft:infested_stone_bricks", {BLOCK_OPAQUE, {122, 121, 122}}}, +{"minecraft:iron_bars", {BLOCK_OPAQUE, {136, 139, 135}}}, +{"minecraft:iron_block", {BLOCK_OPAQUE, {220, 220, 220}}}, +{"minecraft:iron_door", {BLOCK_OPAQUE, {193, 192, 192}}}, +{"minecraft:iron_ore", {BLOCK_OPAQUE, {136, 130, 127}}}, +{"minecraft:iron_trapdoor", {BLOCK_OPAQUE, {202, 202, 202}}}, +{"minecraft:item_frame", {0, {0, 0, 0}}}, +{"minecraft:jack_o_lantern", {BLOCK_OPAQUE, {214, 152, 52}}}, +{"minecraft:jigsaw", {BLOCK_OPAQUE, {80, 69, 81}}}, +{"minecraft:jukebox", {BLOCK_OPAQUE, {93, 64, 47}}}, +{"minecraft:jungle_button", {0, {0, 0, 0}}}, +{"minecraft:jungle_door", {BLOCK_OPAQUE, {163, 119, 84}}}, +{"minecraft:jungle_fence", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_fence_gate", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_leaves", {BLOCK_OPAQUE|BLOCK_FOLIAGE, {156, 154, 143}}}, +{"minecraft:jungle_log", {BLOCK_OPAQUE, {149, 109, 70}}}, +{"minecraft:jungle_planks", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_pressure_plate", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_sapling", {BLOCK_OPAQUE, {47, 81, 16}}}, +{"minecraft:jungle_sign", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_slab", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_stairs", {BLOCK_OPAQUE, {160, 115, 80}}}, +{"minecraft:jungle_trapdoor", {BLOCK_OPAQUE, {152, 110, 77}}}, +{"minecraft:jungle_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:jungle_wood", {BLOCK_OPAQUE, {85, 67, 25}}}, +{"minecraft:kelp", {0, {0, 0, 0}}}, +{"minecraft:kelp_plant", {BLOCK_OPAQUE, {86, 130, 42}}}, +{"minecraft:ladder", {0, {0, 0, 0}}}, +{"minecraft:lantern", {BLOCK_OPAQUE, {106, 91, 83}}}, +{"minecraft:lapis_block", {BLOCK_OPAQUE, {30, 67, 140}}}, +{"minecraft:lapis_ore", {BLOCK_OPAQUE, {99, 110, 132}}}, +{"minecraft:large_fern", {BLOCK_OPAQUE|BLOCK_GRASS, {125, 125, 125}}}, +{"minecraft:lava", {BLOCK_OPAQUE, {212, 90, 18}}}, +{"minecraft:lectern", {BLOCK_OPAQUE, {173, 137, 83}}}, +{"minecraft:lever", {0, {0, 0, 0}}}, +{"minecraft:light_blue_banner", {0, {0, 0, 0}}}, +{"minecraft:light_blue_bed", {0, {0, 0, 0}}}, +{"minecraft:light_blue_carpet", {BLOCK_OPAQUE, {58, 175, 217}}}, +{"minecraft:light_blue_concrete", {BLOCK_OPAQUE, {35, 137, 198}}}, +{"minecraft:light_blue_concrete_powder", {BLOCK_OPAQUE, {74, 180, 213}}}, +{"minecraft:light_blue_glazed_terracotta", {BLOCK_OPAQUE, {94, 164, 208}}}, +{"minecraft:light_blue_shulker_box", {BLOCK_OPAQUE, {49, 163, 212}}}, +{"minecraft:light_blue_stained_glass", {BLOCK_OPAQUE, {102, 153, 216}}}, +{"minecraft:light_blue_stained_glass_pane", {BLOCK_OPAQUE, {97, 147, 208}}}, +{"minecraft:light_blue_terracotta", {BLOCK_OPAQUE, {113, 108, 137}}}, +{"minecraft:light_blue_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:light_blue_wool", {BLOCK_OPAQUE, {58, 175, 217}}}, +{"minecraft:light_gray_banner", {0, {0, 0, 0}}}, +{"minecraft:light_gray_bed", {0, {0, 0, 0}}}, +{"minecraft:light_gray_carpet", {BLOCK_OPAQUE, {142, 142, 134}}}, +{"minecraft:light_gray_concrete", {BLOCK_OPAQUE, {125, 125, 115}}}, +{"minecraft:light_gray_concrete_powder", {BLOCK_OPAQUE, {154, 154, 148}}}, +{"minecraft:light_gray_glazed_terracotta", {BLOCK_OPAQUE, {144, 166, 167}}}, +{"minecraft:light_gray_shulker_box", {BLOCK_OPAQUE, {124, 124, 115}}}, +{"minecraft:light_gray_stained_glass", {BLOCK_OPAQUE, {153, 153, 153}}}, +{"minecraft:light_gray_stained_glass_pane", {BLOCK_OPAQUE, {147, 147, 147}}}, +{"minecraft:light_gray_terracotta", {BLOCK_OPAQUE, {135, 106, 97}}}, +{"minecraft:light_gray_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:light_gray_wool", {BLOCK_OPAQUE, {142, 142, 134}}}, +{"minecraft:light_weighted_pressure_plate", {BLOCK_OPAQUE, {246, 208, 61}}}, +{"minecraft:lilac", {BLOCK_OPAQUE, {154, 125, 147}}}, +{"minecraft:lily_of_the_valley", {0, {0, 0, 0}}}, +{"minecraft:lily_pad", {BLOCK_OPAQUE|BLOCK_GRASS, {133, 133, 133}}}, +{"minecraft:lime_banner", {0, {0, 0, 0}}}, +{"minecraft:lime_bed", {0, {0, 0, 0}}}, +{"minecraft:lime_carpet", {BLOCK_OPAQUE, {112, 185, 25}}}, +{"minecraft:lime_concrete", {BLOCK_OPAQUE, {94, 168, 24}}}, +{"minecraft:lime_concrete_powder", {BLOCK_OPAQUE, {125, 189, 41}}}, +{"minecraft:lime_glazed_terracotta", {BLOCK_OPAQUE, {162, 197, 55}}}, +{"minecraft:lime_shulker_box", {BLOCK_OPAQUE, {99, 172, 23}}}, +{"minecraft:lime_stained_glass", {BLOCK_OPAQUE, {127, 204, 25}}}, +{"minecraft:lime_stained_glass_pane", {BLOCK_OPAQUE, {122, 196, 24}}}, +{"minecraft:lime_terracotta", {BLOCK_OPAQUE, {103, 117, 52}}}, +{"minecraft:lime_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:lime_wool", {BLOCK_OPAQUE, {112, 185, 25}}}, +{"minecraft:lodestone", {BLOCK_OPAQUE, {147, 149, 152}}}, +{"minecraft:loom", {BLOCK_OPAQUE, {142, 119, 91}}}, +{"minecraft:magenta_banner", {0, {0, 0, 0}}}, +{"minecraft:magenta_bed", {0, {0, 0, 0}}}, +{"minecraft:magenta_carpet", {BLOCK_OPAQUE, {189, 68, 179}}}, +{"minecraft:magenta_concrete", {BLOCK_OPAQUE, {169, 48, 159}}}, +{"minecraft:magenta_concrete_powder", {BLOCK_OPAQUE, {192, 83, 184}}}, +{"minecraft:magenta_glazed_terracotta", {BLOCK_OPAQUE, {208, 100, 191}}}, +{"minecraft:magenta_shulker_box", {BLOCK_OPAQUE, {173, 54, 163}}}, +{"minecraft:magenta_stained_glass", {BLOCK_OPAQUE, {178, 76, 216}}}, +{"minecraft:magenta_stained_glass_pane", {BLOCK_OPAQUE, {171, 73, 208}}}, +{"minecraft:magenta_terracotta", {BLOCK_OPAQUE, {149, 88, 108}}}, +{"minecraft:magenta_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:magenta_wool", {BLOCK_OPAQUE, {189, 68, 179}}}, +{"minecraft:magma_block", {BLOCK_OPAQUE, {142, 63, 31}}}, +{"minecraft:melon", {BLOCK_OPAQUE, {111, 144, 30}}}, +{"minecraft:melon_stem", {BLOCK_OPAQUE|BLOCK_GRASS, {153, 153, 153}}}, +{"minecraft:mossy_cobblestone", {BLOCK_OPAQUE, {110, 118, 94}}}, +{"minecraft:mossy_cobblestone_slab", {BLOCK_OPAQUE, {110, 118, 94}}}, +{"minecraft:mossy_cobblestone_stairs", {BLOCK_OPAQUE, {110, 118, 94}}}, +{"minecraft:mossy_cobblestone_wall", {BLOCK_OPAQUE, {110, 118, 94}}}, +{"minecraft:mossy_stone_brick_slab", {BLOCK_OPAQUE, {115, 121, 105}}}, +{"minecraft:mossy_stone_brick_stairs", {BLOCK_OPAQUE, {115, 121, 105}}}, +{"minecraft:mossy_stone_brick_wall", {BLOCK_OPAQUE, {115, 121, 105}}}, +{"minecraft:mossy_stone_bricks", {BLOCK_OPAQUE, {115, 121, 105}}}, +{"minecraft:moving_piston", {0, {0, 0, 0}}}, +{"minecraft:mushroom_stem", {BLOCK_OPAQUE, {203, 196, 185}}}, +{"minecraft:mycelium", {BLOCK_OPAQUE, {111, 98, 101}}}, +{"minecraft:nether_brick_fence", {BLOCK_OPAQUE, {44, 21, 26}}}, +{"minecraft:nether_brick_slab", {BLOCK_OPAQUE, {44, 21, 26}}}, +{"minecraft:nether_brick_stairs", {BLOCK_OPAQUE, {44, 21, 26}}}, +{"minecraft:nether_brick_wall", {BLOCK_OPAQUE, {44, 21, 26}}}, +{"minecraft:nether_bricks", {BLOCK_OPAQUE, {44, 21, 26}}}, +{"minecraft:nether_gold_ore", {BLOCK_OPAQUE, {115, 54, 42}}}, +{"minecraft:nether_portal", {BLOCK_OPAQUE, {89, 11, 192}}}, +{"minecraft:nether_quartz_ore", {BLOCK_OPAQUE, {117, 65, 62}}}, +{"minecraft:nether_sprouts", {BLOCK_OPAQUE, {19, 151, 133}}}, +{"minecraft:nether_wart", {BLOCK_OPAQUE, {111, 18, 19}}}, +{"minecraft:nether_wart_block", {BLOCK_OPAQUE, {114, 2, 2}}}, +{"minecraft:netherite_block", {BLOCK_OPAQUE, {66, 61, 63}}}, +{"minecraft:netherrack", {BLOCK_OPAQUE, {97, 38, 38}}}, +{"minecraft:note_block", {BLOCK_OPAQUE, {88, 58, 40}}}, +{"minecraft:oak_button", {0, {0, 0, 0}}}, +{"minecraft:oak_door", {BLOCK_OPAQUE, {139, 110, 65}}}, +{"minecraft:oak_fence", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_fence_gate", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_leaves", {BLOCK_OPAQUE|BLOCK_FOLIAGE, {144, 144, 144}}}, +{"minecraft:oak_log", {BLOCK_OPAQUE, {151, 121, 73}}}, +{"minecraft:oak_planks", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_pressure_plate", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_sapling", {BLOCK_OPAQUE, {77, 106, 40}}}, +{"minecraft:oak_sign", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_slab", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_stairs", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:oak_trapdoor", {BLOCK_OPAQUE, {124, 99, 56}}}, +{"minecraft:oak_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:oak_wood", {BLOCK_OPAQUE, {109, 85, 50}}}, +{"minecraft:observer", {BLOCK_OPAQUE, {98, 98, 98}}}, +{"minecraft:obsidian", {BLOCK_OPAQUE, {15, 10, 24}}}, +{"minecraft:orange_banner", {0, {0, 0, 0}}}, +{"minecraft:orange_bed", {0, {0, 0, 0}}}, +{"minecraft:orange_carpet", {BLOCK_OPAQUE, {240, 118, 19}}}, +{"minecraft:orange_concrete", {BLOCK_OPAQUE, {224, 97, 0}}}, +{"minecraft:orange_concrete_powder", {BLOCK_OPAQUE, {227, 131, 31}}}, +{"minecraft:orange_glazed_terracotta", {BLOCK_OPAQUE, {154, 147, 91}}}, +{"minecraft:orange_shulker_box", {BLOCK_OPAQUE, {234, 106, 8}}}, +{"minecraft:orange_stained_glass", {BLOCK_OPAQUE, {216, 127, 51}}}, +{"minecraft:orange_stained_glass_pane", {BLOCK_OPAQUE, {208, 122, 48}}}, +{"minecraft:orange_terracotta", {BLOCK_OPAQUE, {161, 83, 37}}}, +{"minecraft:orange_tulip", {0, {0, 0, 0}}}, +{"minecraft:orange_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:orange_wool", {BLOCK_OPAQUE, {240, 118, 19}}}, +{"minecraft:oxeye_daisy", {0, {0, 0, 0}}}, +{"minecraft:packed_ice", {BLOCK_OPAQUE, {141, 180, 250}}}, +{"minecraft:peony", {BLOCK_OPAQUE, {129, 126, 139}}}, +{"minecraft:petrified_oak_slab", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:pink_banner", {0, {0, 0, 0}}}, +{"minecraft:pink_bed", {0, {0, 0, 0}}}, +{"minecraft:pink_carpet", {BLOCK_OPAQUE, {237, 141, 172}}}, +{"minecraft:pink_concrete", {BLOCK_OPAQUE, {213, 101, 142}}}, +{"minecraft:pink_concrete_powder", {BLOCK_OPAQUE, {228, 153, 181}}}, +{"minecraft:pink_glazed_terracotta", {BLOCK_OPAQUE, {235, 154, 181}}}, +{"minecraft:pink_shulker_box", {BLOCK_OPAQUE, {230, 121, 157}}}, +{"minecraft:pink_stained_glass", {BLOCK_OPAQUE, {242, 127, 165}}}, +{"minecraft:pink_stained_glass_pane", {BLOCK_OPAQUE, {233, 122, 159}}}, +{"minecraft:pink_terracotta", {BLOCK_OPAQUE, {161, 78, 78}}}, +{"minecraft:pink_tulip", {0, {0, 0, 0}}}, +{"minecraft:pink_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:pink_wool", {BLOCK_OPAQUE, {237, 141, 172}}}, +{"minecraft:piston", {BLOCK_OPAQUE, {110, 104, 96}}}, +{"minecraft:piston_head", {BLOCK_OPAQUE, {154, 127, 87}}}, +{"minecraft:player_head", {0, {0, 0, 0}}}, +{"minecraft:player_wall_head", {0, {0, 0, 0}}}, +{"minecraft:podzol", {BLOCK_OPAQUE, {91, 63, 24}}}, +{"minecraft:polished_andesite", {BLOCK_OPAQUE, {132, 134, 133}}}, +{"minecraft:polished_andesite_slab", {BLOCK_OPAQUE, {132, 134, 133}}}, +{"minecraft:polished_andesite_stairs", {BLOCK_OPAQUE, {132, 134, 133}}}, +{"minecraft:polished_basalt", {BLOCK_OPAQUE, {99, 98, 100}}}, +{"minecraft:polished_blackstone", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:polished_blackstone_brick_slab", {BLOCK_OPAQUE, {46, 41, 48}}}, +{"minecraft:polished_blackstone_brick_stairs", {BLOCK_OPAQUE, {46, 41, 48}}}, +{"minecraft:polished_blackstone_brick_wall", {BLOCK_OPAQUE, {46, 41, 48}}}, +{"minecraft:polished_blackstone_bricks", {BLOCK_OPAQUE, {46, 41, 48}}}, +{"minecraft:polished_blackstone_button", {0, {0, 0, 0}}}, +{"minecraft:polished_blackstone_pressure_plate", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:polished_blackstone_slab", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:polished_blackstone_stairs", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:polished_blackstone_wall", {BLOCK_OPAQUE, {53, 48, 56}}}, +{"minecraft:polished_diorite", {BLOCK_OPAQUE, {192, 193, 194}}}, +{"minecraft:polished_diorite_slab", {BLOCK_OPAQUE, {192, 193, 194}}}, +{"minecraft:polished_diorite_stairs", {BLOCK_OPAQUE, {192, 193, 194}}}, +{"minecraft:polished_granite", {BLOCK_OPAQUE, {154, 106, 89}}}, +{"minecraft:polished_granite_slab", {BLOCK_OPAQUE, {154, 106, 89}}}, +{"minecraft:polished_granite_stairs", {BLOCK_OPAQUE, {154, 106, 89}}}, +{"minecraft:poppy", {0, {0, 0, 0}}}, +{"minecraft:potatoes", {BLOCK_OPAQUE, {84, 135, 47}}}, +{"minecraft:potted_acacia_sapling", {BLOCK_OPAQUE, {118, 117, 23}}}, +{"minecraft:potted_allium", {BLOCK_OPAQUE, {158, 137, 183}}}, +{"minecraft:potted_azure_bluet", {BLOCK_OPAQUE, {169, 204, 127}}}, +{"minecraft:potted_bamboo", {BLOCK_OPAQUE, {93, 144, 19}}}, +{"minecraft:potted_birch_sapling", {BLOCK_OPAQUE, {127, 160, 79}}}, +{"minecraft:potted_blue_orchid", {BLOCK_OPAQUE, {47, 162, 168}}}, +{"minecraft:potted_brown_mushroom", {BLOCK_OPAQUE, {153, 116, 92}}}, +{"minecraft:potted_cactus", {BLOCK_OPAQUE, {85, 127, 43}}}, +{"minecraft:potted_cornflower", {BLOCK_OPAQUE, {79, 121, 146}}}, +{"minecraft:potted_crimson_fungus", {BLOCK_OPAQUE, {141, 44, 29}}}, +{"minecraft:potted_crimson_roots", {BLOCK_OPAQUE, {127, 8, 41}}}, +{"minecraft:potted_dandelion", {BLOCK_OPAQUE, {147, 172, 43}}}, +{"minecraft:potted_dark_oak_sapling", {BLOCK_OPAQUE, {61, 90, 30}}}, +{"minecraft:potted_dead_bush", {BLOCK_OPAQUE, {107, 78, 40}}}, +{"minecraft:potted_fern", {BLOCK_OPAQUE|BLOCK_GRASS, {124, 124, 124}}}, +{"minecraft:potted_jungle_sapling", {BLOCK_OPAQUE, {47, 81, 16}}}, +{"minecraft:potted_lily_of_the_valley", {BLOCK_OPAQUE, {123, 174, 95}}}, +{"minecraft:potted_oak_sapling", {BLOCK_OPAQUE, {77, 106, 40}}}, +{"minecraft:potted_orange_tulip", {BLOCK_OPAQUE, {93, 142, 30}}}, +{"minecraft:potted_oxeye_daisy", {BLOCK_OPAQUE, {179, 202, 143}}}, +{"minecraft:potted_pink_tulip", {BLOCK_OPAQUE, {99, 157, 78}}}, +{"minecraft:potted_poppy", {BLOCK_OPAQUE, {128, 64, 37}}}, +{"minecraft:potted_red_mushroom", {BLOCK_OPAQUE, {216, 75, 67}}}, +{"minecraft:potted_red_tulip", {BLOCK_OPAQUE, {89, 128, 32}}}, +{"minecraft:potted_spruce_sapling", {BLOCK_OPAQUE, {44, 60, 36}}}, +{"minecraft:potted_warped_fungus", {BLOCK_OPAQUE, {74, 109, 87}}}, +{"minecraft:potted_warped_roots", {BLOCK_OPAQUE, {20, 136, 123}}}, +{"minecraft:potted_white_tulip", {BLOCK_OPAQUE, {93, 164, 71}}}, +{"minecraft:potted_wither_rose", {BLOCK_OPAQUE, {41, 44, 23}}}, +{"minecraft:powered_rail", {BLOCK_OPAQUE, {137, 109, 74}}}, +{"minecraft:prismarine", {BLOCK_OPAQUE, {99, 156, 151}}}, +{"minecraft:prismarine_brick_slab", {BLOCK_OPAQUE, {99, 171, 158}}}, +{"minecraft:prismarine_brick_stairs", {BLOCK_OPAQUE, {99, 171, 158}}}, +{"minecraft:prismarine_bricks", {BLOCK_OPAQUE, {99, 171, 158}}}, +{"minecraft:prismarine_slab", {BLOCK_OPAQUE, {99, 156, 151}}}, +{"minecraft:prismarine_stairs", {BLOCK_OPAQUE, {99, 156, 151}}}, +{"minecraft:prismarine_wall", {BLOCK_OPAQUE, {99, 156, 151}}}, +{"minecraft:pumpkin", {BLOCK_OPAQUE, {198, 118, 24}}}, +{"minecraft:pumpkin_stem", {BLOCK_OPAQUE|BLOCK_GRASS, {154, 154, 154}}}, +{"minecraft:purple_banner", {0, {0, 0, 0}}}, +{"minecraft:purple_bed", {0, {0, 0, 0}}}, +{"minecraft:purple_carpet", {BLOCK_OPAQUE, {121, 42, 172}}}, +{"minecraft:purple_concrete", {BLOCK_OPAQUE, {100, 31, 156}}}, +{"minecraft:purple_concrete_powder", {BLOCK_OPAQUE, {131, 55, 177}}}, +{"minecraft:purple_glazed_terracotta", {BLOCK_OPAQUE, {109, 48, 152}}}, +{"minecraft:purple_shulker_box", {BLOCK_OPAQUE, {103, 32, 156}}}, +{"minecraft:purple_stained_glass", {BLOCK_OPAQUE, {127, 63, 178}}}, +{"minecraft:purple_stained_glass_pane", {BLOCK_OPAQUE, {122, 61, 171}}}, +{"minecraft:purple_terracotta", {BLOCK_OPAQUE, {118, 70, 86}}}, +{"minecraft:purple_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:purple_wool", {BLOCK_OPAQUE, {121, 42, 172}}}, +{"minecraft:purpur_block", {BLOCK_OPAQUE, {169, 125, 169}}}, +{"minecraft:purpur_pillar", {BLOCK_OPAQUE, {171, 129, 171}}}, +{"minecraft:purpur_slab", {BLOCK_OPAQUE, {169, 125, 169}}}, +{"minecraft:purpur_stairs", {BLOCK_OPAQUE, {169, 125, 169}}}, +{"minecraft:quartz_block", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:quartz_bricks", {BLOCK_OPAQUE, {234, 229, 221}}}, +{"minecraft:quartz_pillar", {BLOCK_OPAQUE, {235, 230, 224}}}, +{"minecraft:quartz_slab", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:quartz_stairs", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:rail", {BLOCK_OPAQUE, {125, 111, 88}}}, +{"minecraft:red_banner", {0, {0, 0, 0}}}, +{"minecraft:red_bed", {0, {0, 0, 0}}}, +{"minecraft:red_carpet", {BLOCK_OPAQUE, {160, 39, 34}}}, +{"minecraft:red_concrete", {BLOCK_OPAQUE, {142, 32, 32}}}, +{"minecraft:red_concrete_powder", {BLOCK_OPAQUE, {168, 54, 50}}}, +{"minecraft:red_glazed_terracotta", {BLOCK_OPAQUE, {181, 59, 53}}}, +{"minecraft:red_mushroom", {0, {0, 0, 0}}}, +{"minecraft:red_mushroom_block", {BLOCK_OPAQUE, {200, 46, 45}}}, +{"minecraft:red_nether_brick_slab", {BLOCK_OPAQUE, {69, 7, 9}}}, +{"minecraft:red_nether_brick_stairs", {BLOCK_OPAQUE, {69, 7, 9}}}, +{"minecraft:red_nether_brick_wall", {BLOCK_OPAQUE, {69, 7, 9}}}, +{"minecraft:red_nether_bricks", {BLOCK_OPAQUE, {69, 7, 9}}}, +{"minecraft:red_sand", {BLOCK_OPAQUE, {190, 102, 33}}}, +{"minecraft:red_sandstone", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:red_sandstone_slab", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:red_sandstone_stairs", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:red_sandstone_wall", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:red_shulker_box", {BLOCK_OPAQUE, {140, 31, 30}}}, +{"minecraft:red_stained_glass", {BLOCK_OPAQUE, {153, 51, 51}}}, +{"minecraft:red_stained_glass_pane", {BLOCK_OPAQUE, {147, 48, 48}}}, +{"minecraft:red_terracotta", {BLOCK_OPAQUE, {143, 61, 46}}}, +{"minecraft:red_tulip", {0, {0, 0, 0}}}, +{"minecraft:red_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:red_wool", {BLOCK_OPAQUE, {160, 39, 34}}}, +{"minecraft:redstone_block", {BLOCK_OPAQUE, {175, 24, 5}}}, +{"minecraft:redstone_lamp", {BLOCK_OPAQUE, {95, 54, 30}}}, +{"minecraft:redstone_ore", {BLOCK_OPAQUE, {133, 107, 107}}}, +{"minecraft:redstone_torch", {0, {0, 0, 0}}}, +{"minecraft:redstone_wall_torch", {0, {0, 0, 0}}}, +{"minecraft:redstone_wire", {BLOCK_OPAQUE, {175, 24, 5}}}, +{"minecraft:repeater", {BLOCK_OPAQUE, {160, 157, 156}}}, +{"minecraft:repeating_command_block", {BLOCK_OPAQUE, {129, 111, 176}}}, +{"minecraft:respawn_anchor", {BLOCK_OPAQUE, {75, 26, 144}}}, +{"minecraft:rose_bush", {BLOCK_OPAQUE, {131, 66, 37}}}, +{"minecraft:sand", {BLOCK_OPAQUE, {219, 207, 163}}}, +{"minecraft:sandstone", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:sandstone_slab", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:sandstone_stairs", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:sandstone_wall", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:scaffolding", {BLOCK_OPAQUE, {174, 134, 80}}}, +{"minecraft:sea_lantern", {BLOCK_OPAQUE, {172, 199, 190}}}, +{"minecraft:sea_pickle", {BLOCK_OPAQUE, {90, 97, 39}}}, +{"minecraft:seagrass", {0, {0, 0, 0}}}, +{"minecraft:shroomlight", {BLOCK_OPAQUE, {240, 146, 70}}}, +{"minecraft:shulker_box", {BLOCK_OPAQUE, {139, 96, 139}}}, +{"minecraft:sign", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:skeleton_skull", {0, {0, 0, 0}}}, +{"minecraft:skeleton_wall_skull", {0, {0, 0, 0}}}, +{"minecraft:slime_block", {BLOCK_OPAQUE, {111, 192, 91}}}, +{"minecraft:smithing_table", {BLOCK_OPAQUE, {57, 58, 70}}}, +{"minecraft:smoker", {BLOCK_OPAQUE, {84, 82, 80}}}, +{"minecraft:smooth_quartz", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:smooth_quartz_slab", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:smooth_quartz_stairs", {BLOCK_OPAQUE, {235, 229, 222}}}, +{"minecraft:smooth_red_sandstone", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:smooth_red_sandstone_slab", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:smooth_red_sandstone_stairs", {BLOCK_OPAQUE, {181, 97, 31}}}, +{"minecraft:smooth_sandstone", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:smooth_sandstone_slab", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:smooth_sandstone_stairs", {BLOCK_OPAQUE, {223, 214, 170}}}, +{"minecraft:smooth_stone", {BLOCK_OPAQUE, {158, 158, 158}}}, +{"minecraft:smooth_stone_slab", {BLOCK_OPAQUE, {158, 158, 158}}}, +{"minecraft:snow", {BLOCK_OPAQUE, {249, 254, 254}}}, +{"minecraft:snow_block", {BLOCK_OPAQUE, {249, 254, 254}}}, +{"minecraft:soul_campfire", {BLOCK_OPAQUE, {80, 204, 208}}}, +{"minecraft:soul_fire", {BLOCK_OPAQUE, {51, 192, 197}}}, +{"minecraft:soul_lantern", {BLOCK_OPAQUE, {71, 99, 114}}}, +{"minecraft:soul_sand", {BLOCK_OPAQUE, {81, 62, 50}}}, +{"minecraft:soul_soil", {BLOCK_OPAQUE, {75, 57, 46}}}, +{"minecraft:soul_torch", {0, {0, 0, 0}}}, +{"minecraft:soul_wall_torch", {0, {0, 0, 0}}}, +{"minecraft:spawner", {BLOCK_OPAQUE, {36, 46, 62}}}, +{"minecraft:sponge", {BLOCK_OPAQUE, {195, 192, 74}}}, +{"minecraft:spruce_button", {0, {0, 0, 0}}}, +{"minecraft:spruce_door", {BLOCK_OPAQUE, {106, 80, 48}}}, +{"minecraft:spruce_fence", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_fence_gate", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_leaves", {BLOCK_OPAQUE|BLOCK_SPRUCE, {126, 126, 126}}}, +{"minecraft:spruce_log", {BLOCK_OPAQUE, {108, 80, 46}}}, +{"minecraft:spruce_planks", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_pressure_plate", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_sapling", {BLOCK_OPAQUE, {44, 60, 36}}}, +{"minecraft:spruce_sign", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_slab", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_stairs", {BLOCK_OPAQUE, {114, 84, 48}}}, +{"minecraft:spruce_trapdoor", {BLOCK_OPAQUE, {103, 79, 47}}}, +{"minecraft:spruce_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:spruce_wood", {BLOCK_OPAQUE, {58, 37, 16}}}, +{"minecraft:sticky_piston", {BLOCK_OPAQUE, {110, 104, 96}}}, +{"minecraft:stone", {BLOCK_OPAQUE, {125, 125, 125}}}, +{"minecraft:stone_brick_slab", {BLOCK_OPAQUE, {122, 121, 122}}}, +{"minecraft:stone_brick_stairs", {BLOCK_OPAQUE, {122, 121, 122}}}, +{"minecraft:stone_brick_wall", {BLOCK_OPAQUE, {122, 121, 122}}}, +{"minecraft:stone_bricks", {BLOCK_OPAQUE, {122, 121, 122}}}, +{"minecraft:stone_button", {0, {0, 0, 0}}}, +{"minecraft:stone_pressure_plate", {BLOCK_OPAQUE, {125, 125, 125}}}, +{"minecraft:stone_slab", {BLOCK_OPAQUE, {125, 125, 125}}}, +{"minecraft:stone_stairs", {BLOCK_OPAQUE, {125, 125, 125}}}, +{"minecraft:stonecutter", {BLOCK_OPAQUE, {123, 118, 111}}}, +{"minecraft:stripped_acacia_log", {BLOCK_OPAQUE, {166, 91, 51}}}, +{"minecraft:stripped_acacia_wood", {BLOCK_OPAQUE, {174, 92, 59}}}, +{"minecraft:stripped_birch_log", {BLOCK_OPAQUE, {191, 171, 116}}}, +{"minecraft:stripped_birch_wood", {BLOCK_OPAQUE, {196, 176, 118}}}, +{"minecraft:stripped_crimson_hyphae", {BLOCK_OPAQUE, {137, 57, 90}}}, +{"minecraft:stripped_crimson_stem", {BLOCK_OPAQUE, {121, 56, 82}}}, +{"minecraft:stripped_dark_oak_log", {BLOCK_OPAQUE, {65, 44, 22}}}, +{"minecraft:stripped_dark_oak_wood", {BLOCK_OPAQUE, {96, 76, 49}}}, +{"minecraft:stripped_jungle_log", {BLOCK_OPAQUE, {165, 122, 81}}}, +{"minecraft:stripped_jungle_wood", {BLOCK_OPAQUE, {171, 132, 84}}}, +{"minecraft:stripped_oak_log", {BLOCK_OPAQUE, {160, 129, 77}}}, +{"minecraft:stripped_oak_wood", {BLOCK_OPAQUE, {177, 144, 86}}}, +{"minecraft:stripped_spruce_log", {BLOCK_OPAQUE, {105, 80, 46}}}, +{"minecraft:stripped_spruce_wood", {BLOCK_OPAQUE, {115, 89, 52}}}, +{"minecraft:stripped_warped_hyphae", {BLOCK_OPAQUE, {57, 150, 147}}}, +{"minecraft:stripped_warped_stem", {BLOCK_OPAQUE, {52, 128, 124}}}, +{"minecraft:structure_block", {BLOCK_OPAQUE, {88, 74, 90}}}, +{"minecraft:structure_void", {0, {0, 0, 0}}}, +{"minecraft:sugar_cane", {BLOCK_OPAQUE, {148, 192, 101}}}, +{"minecraft:sunflower", {BLOCK_OPAQUE, {246, 196, 54}}}, +{"minecraft:sweet_berry_bush", {BLOCK_OPAQUE, {68, 77, 50}}}, +{"minecraft:tall_grass", {BLOCK_OPAQUE|BLOCK_GRASS, {151, 149, 151}}}, +{"minecraft:tall_seagrass", {BLOCK_OPAQUE, {59, 139, 14}}}, +{"minecraft:target", {BLOCK_OPAQUE, {226, 170, 157}}}, +{"minecraft:terracotta", {BLOCK_OPAQUE, {152, 94, 67}}}, +{"minecraft:tnt", {BLOCK_OPAQUE, {142, 62, 53}}}, +{"minecraft:torch", {0, {0, 0, 0}}}, +{"minecraft:trapped_chest", {BLOCK_OPAQUE, {162, 130, 78}}}, +{"minecraft:tripwire", {0, {0, 0, 0}}}, +{"minecraft:tripwire_hook", {0, {0, 0, 0}}}, +{"minecraft:tube_coral", {0, {0, 0, 0}}}, +{"minecraft:tube_coral_block", {BLOCK_OPAQUE, {49, 87, 206}}}, +{"minecraft:tube_coral_fan", {0, {0, 0, 0}}}, +{"minecraft:tube_coral_wall_fan", {0, {0, 0, 0}}}, +{"minecraft:turtle_egg", {BLOCK_OPAQUE, {228, 226, 191}}}, +{"minecraft:twisting_vines", {BLOCK_OPAQUE, {20, 143, 124}}}, +{"minecraft:twisting_vines_plant", {BLOCK_OPAQUE, {20, 135, 122}}}, +{"minecraft:vine", {BLOCK_OPAQUE|BLOCK_GRASS, {116, 116, 116}}}, +{"minecraft:void_air", {0, {0, 0, 0}}}, +{"minecraft:wall_sign", {0, {0, 0, 0}}}, +{"minecraft:wall_torch", {0, {0, 0, 0}}}, +{"minecraft:warped_button", {0, {0, 0, 0}}}, +{"minecraft:warped_door", {BLOCK_OPAQUE, {44, 126, 120}}}, +{"minecraft:warped_fence", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_fence_gate", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_fungus", {0, {0, 0, 0}}}, +{"minecraft:warped_hyphae", {BLOCK_OPAQUE, {58, 58, 77}}}, +{"minecraft:warped_nylium", {BLOCK_OPAQUE, {43, 114, 101}}}, +{"minecraft:warped_planks", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_pressure_plate", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_roots", {BLOCK_OPAQUE, {20, 138, 124}}}, +{"minecraft:warped_sign", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_slab", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_stairs", {BLOCK_OPAQUE, {43, 104, 99}}}, +{"minecraft:warped_stem", {BLOCK_OPAQUE, {57, 103, 103}}}, +{"minecraft:warped_trapdoor", {BLOCK_OPAQUE, {47, 119, 111}}}, +{"minecraft:warped_wall_sign", {0, {0, 0, 0}}}, +{"minecraft:warped_wart_block", {BLOCK_OPAQUE, {22, 119, 121}}}, +{"minecraft:water", {BLOCK_OPAQUE|BLOCK_WATER, {177, 177, 177}}}, +{"minecraft:weeping_vines", {BLOCK_OPAQUE, {104, 1, 0}}}, +{"minecraft:weeping_vines_plant", {BLOCK_OPAQUE, {132, 16, 12}}}, +{"minecraft:wet_sponge", {BLOCK_OPAQUE, {171, 181, 70}}}, +{"minecraft:wheat", {BLOCK_OPAQUE, {166, 151, 73}}}, +{"minecraft:white_banner", {0, {0, 0, 0}}}, +{"minecraft:white_bed", {0, {0, 0, 0}}}, +{"minecraft:white_carpet", {BLOCK_OPAQUE, {233, 236, 236}}}, +{"minecraft:white_concrete", {BLOCK_OPAQUE, {207, 213, 214}}}, +{"minecraft:white_concrete_powder", {BLOCK_OPAQUE, {225, 227, 227}}}, +{"minecraft:white_glazed_terracotta", {BLOCK_OPAQUE, {188, 212, 202}}}, +{"minecraft:white_shulker_box", {BLOCK_OPAQUE, {215, 220, 221}}}, +{"minecraft:white_stained_glass", {BLOCK_OPAQUE, {255, 255, 255}}}, +{"minecraft:white_stained_glass_pane", {BLOCK_OPAQUE, {246, 246, 246}}}, +{"minecraft:white_terracotta", {BLOCK_OPAQUE, {209, 178, 161}}}, +{"minecraft:white_tulip", {0, {0, 0, 0}}}, +{"minecraft:white_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:white_wool", {BLOCK_OPAQUE, {233, 236, 236}}}, +{"minecraft:wither_rose", {0, {0, 0, 0}}}, +{"minecraft:wither_skeleton_skull", {0, {0, 0, 0}}}, +{"minecraft:wither_skeleton_wall_skull", {0, {0, 0, 0}}}, +{"minecraft:yellow_banner", {0, {0, 0, 0}}}, +{"minecraft:yellow_bed", {0, {0, 0, 0}}}, +{"minecraft:yellow_carpet", {BLOCK_OPAQUE, {248, 197, 39}}}, +{"minecraft:yellow_concrete", {BLOCK_OPAQUE, {240, 175, 21}}}, +{"minecraft:yellow_concrete_powder", {BLOCK_OPAQUE, {232, 199, 54}}}, +{"minecraft:yellow_glazed_terracotta", {BLOCK_OPAQUE, {234, 192, 88}}}, +{"minecraft:yellow_shulker_box", {BLOCK_OPAQUE, {248, 188, 29}}}, +{"minecraft:yellow_stained_glass", {BLOCK_OPAQUE, {229, 229, 51}}}, +{"minecraft:yellow_stained_glass_pane", {BLOCK_OPAQUE, {221, 221, 48}}}, +{"minecraft:yellow_terracotta", {BLOCK_OPAQUE, {186, 133, 35}}}, +{"minecraft:yellow_wall_banner", {0, {0, 0, 0}}}, +{"minecraft:yellow_wool", {BLOCK_OPAQUE, {248, 197, 39}}}, +{"minecraft:zombie_head", {0, {0, 0, 0}}}, +{"minecraft:zombie_wall_head", {0, {0, 0, 0}}}, diff --git a/src/Resource/Color.hpp b/src/Resource/Color.hpp new file mode 100644 index 0000000..bad2df6 --- /dev/null +++ b/src/Resource/Color.hpp @@ -0,0 +1,71 @@ +/* + Copyright (c) 2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include + + +namespace MinedMap { +namespace Resource { + +struct FloatColor { + float r, g, b; +}; + +static inline FloatColor operator+(const FloatColor &a, const FloatColor &b){ + return FloatColor { + a.r+b.r, + a.g+b.g, + a.b+b.b, + }; +} + +static inline FloatColor & operator*=(FloatColor &a, const FloatColor &b) { + a.r *= b.r; + a.g *= b.g; + a.b *= b.b; + + return a; +} + +static inline FloatColor operator*(float s, const FloatColor &c) { + return FloatColor { + s*c.r, + s*c.g, + s*c.b, + }; +} + +struct Color { + uint8_t r, g, b, a; + + Color() : r(0), g(0), b(0), a(0) {} + Color(FloatColor c) : r(c.r), g(c.g), b(c.b), a(0xff) {} +}; + +} +} diff --git a/src/Resource/LegacyBlockType.inc b/src/Resource/LegacyBlockType.inc new file mode 100644 index 0000000..b1dcdff --- /dev/null +++ b/src/Resource/LegacyBlockType.inc @@ -0,0 +1,597 @@ +/* 0 */ simple("air"), +/* 1 */ { + "stone", + "granite", + "polished_granite", + "diorite", + "polished_diorite", + "andesite", + "polished_andesite", +}, +/* 2 */ simple("grass_block"), +/* 3 */ { + "dirt", + "coarse_dirt", + "podzol", +}, +/* 4 */ simple("cobblestone"), +/* 5 */ { + "oak_planks", + "spruce_planks", + "birch_planks", + "jungle_planks", + "acacia_planks", + "dark_oak_planks", +}, +/* 6 */ { + "oak_sapling", + "spruce_sapling", + "birch_sapling", + "jungle_sapling", + "acacia_sapling", + "dark_oak_sapling", + nullptr, + nullptr, + "oak_sapling", + "spruce_sapling", + "birch_sapling", + "jungle_sapling", + "acacia_sapling", + "dark_oak_sapling", +}, +/* 7 */ simple("bedrock"), +/* 8 */ simple("water"), +/* 9 */ simple("water"), +/* 10 */ simple("lava"), +/* 11 */ simple("lava"), +/* 12 */ { + "sand", + "red_sand", +}, +/* 13 */ simple("gravel"), +/* 14 */ simple("gold_ore"), +/* 15 */ simple("iron_ore"), +/* 16 */ simple("coal_ore"), +/* 17 */ { + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", + "oak_log", + "spruce_log", + "birch_log", + "jungle_log", +}, +/* 18 */ { + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", + "oak_leaves", + "spruce_leaves", + "birch_leaves", + "jungle_leaves", +}, +/* 19 */ simple("sponge"), +/* 20 */ simple("glass"), +/* 21 */ simple("lapis_ore"), +/* 22 */ simple("lapis_block"), +/* 23 */ simple("dispenser"), +/* 24 */ simple("sandstone"), +/* 25 */ simple("note_block"), +/* 26 */ {/* bed */}, +/* 27 */ simple("powered_rail"), +/* 28 */ simple("detector_rail"), +/* 29 */ simple("sticky_piston"), +/* 30 */ simple("cobweb"), +/* 31 */ { + "grass", + "fern", +}, +/* 32 */ simple("dead_bush"), +/* 33 */ simple("piston"), +/* 34 */ simple("piston_head"), +/* 35 */ { + "white_wool", + "orange_wool", + "magenta_wool", + "light_blue_wool", + "yellow_wool", + "lime_wool", + "pink_wool", + "gray_wool", + "light_gray_wool", + "cyan_wool", + "purple_wool", + "blue_wool", + "brown_wool", + "green_wool", + "red_wool", + "black_wool", +}, +/* 36 */ simple("moving_piston"), +/* 37 */ simple("dandelion"), +/* 38 */ { + "poppy", + "blue_orchid", + "allium", + "azure_bluet", + "red_tulip", + "orange_tulip", + "white_tulip", + "pink_tulip", + "oxeye_daisy", +}, +/* 39 */ simple("brown_mushroom"), +/* 40 */ simple("red_mushroom"), +/* 41 */ simple("gold_block"), +/* 42 */ simple("iron_block"), +/* 43 */ { + "smooth_stone_slab", + "sandstone_slab", + "oak_slab", + "cobblestone_slab", + "brick_slab", + "stone_brick_slab", + "nether_brick_slab", + "quartz_slab", +}, +/* 44 */ { + "smooth_stone_slab", + "sandstone_slab", + "oak_slab", + "cobblestone_slab", + "brick_slab", + "stone_brick_slab", + "nether_brick_slab", + "quartz_slab", + "stone_slab", + "sandstone_slab", + "oak_slab", + "cobblestone_slab", + "brick_slab", + "stone_brick_slab", + "nether_brick_slab", + "quartz_slab", +}, +/* 45 */ simple("bricks"), +/* 46 */ simple("tnt"), +/* 47 */ simple("bookshelf"), +/* 48 */ simple("mossy_cobblestone"), +/* 49 */ simple("obsidian"), +/* 50 */ { + nullptr, + "wall_torch", + "wall_torch", + "wall_torch", + "wall_torch", + "torch", +}, +/* 51 */ simple("fire"), +/* 52 */ simple("spawner"), +/* 53 */ simple("oak_stairs"), +/* 54 */ simple("chest"), +/* 55 */ simple("redstone_wire"), +/* 56 */ simple("diamond_ore"), +/* 57 */ simple("diamond_block"), +/* 58 */ simple("crafting_table"), +/* 59 */ simple("wheat"), +/* 60 */ simple("farmland"), +/* 61 */ simple("furnace"), +/* 62 */ simple("furnace"), +/* 63 */ simple("sign"), +/* 64 */ simple("oak_door"), +/* 65 */ simple("ladder"), +/* 66 */ simple("rail"), +/* 67 */ simple("cobblestone_stairs"), +/* 68 */ simple("wall_sign"), +/* 69 */ simple("lever"), +/* 70 */ simple("stone_pressure_plate"), +/* 71 */ simple("iron_door"), +/* 72 */ simple("oak_pressure_plate"), +/* 73 */ simple("redstone_ore"), +/* 74 */ simple("redstone_ore"), +/* 75 */ { + nullptr, + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_torch", +}, +/* 76 */ { + nullptr, + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_wall_torch", + "redstone_torch", +}, +/* 77 */ simple("stone_button"), +/* 78 */ simple("snow"), +/* 79 */ simple("ice"), +/* 80 */ simple("snow_block"), +/* 81 */ simple("cactus"), +/* 82 */ simple("clay"), +/* 83 */ simple("sugar_cane"), +/* 84 */ simple("jukebox"), +/* 85 */ simple("oak_fence"), +/* 86 */ simple("pumpkin"), +/* 87 */ simple("netherrack"), +/* 88 */ simple("soul_sand"), +/* 89 */ simple("glowstone"), +/* 90 */ simple("nether_portal"), +/* 91 */ simple("pumpkin"), +/* 92 */ simple("cake"), +/* 93 */ simple("repeater"), +/* 94 */ simple("repeater"), +/* 95 */ { + "white_stained_glass", + "orange_stained_glass", + "magenta_stained_glass", + "light_blue_stained_glass", + "yellow_stained_glass", + "lime_stained_glass", + "pink_stained_glass", + "gray_stained_glass", + "light_gray_stained_glass", + "cyan_stained_glass", + "purple_stained_glass", + "blue_stained_glass", + "brown_stained_glass", + "green_stained_glass", + "red_stained_glass", + "black_stained_glass", +}, +/* 96 */ simple("oak_trapdoor"), +/* 97 */ { + "infested_stone", + "infested_cobblestone", + "infested_stone_bricks", + "infested_mossy_stone_bricks", + "infested_cracked_stone_bricks", + "infested_chiseled_stone_bricks", +}, +/* 98 */ { + "stone_bricks", + "mossy_stone_bricks", + "cracked_stone_bricks", + "chiseled_stone_bricks", +}, +/* 99 */ simple("brown_mushroom_block"), +/* 100 */ simple("red_mushroom_block"), +/* 101 */ simple("iron_bars"), +/* 102 */ simple("glass_pane"), +/* 103 */ simple("melon"), +/* 104 */ simple("pumpkin_stem"), +/* 105 */ simple("melon_stem"), +/* 106 */ simple("vine"), +/* 107 */ simple("oak_fence_gate"), +/* 108 */ simple("brick_stairs"), +/* 109 */ simple("stone_brick_stairs"), +/* 110 */ simple("mycelium"), +/* 111 */ simple("lily_pad"), +/* 112 */ simple("nether_bricks"), +/* 113 */ simple("nether_brick_fence"), +/* 114 */ simple("nether_brick_stairs"), +/* 115 */ simple("nether_wart"), +/* 116 */ simple("enchanting_table"), +/* 117 */ simple("brewing_stand"), +/* 118 */ simple("cauldron"), +/* 119 */ simple("end_portal"), +/* 120 */ simple("end_portal_frame"), +/* 121 */ simple("end_stone"), +/* 122 */ simple("dragon_egg"), +/* 123 */ simple("redstone_lamp"), +/* 124 */ simple("redstone_lamp"), +/* 125 */ { + "oak_slab", + "spruce_slab", + "birch_slab", + "jungle_slab", + "acacia_slab", + "dark_oak_slab", +}, +/* 126 */ { + "oak_slab", + "spruce_slab", + "birch_slab", + "jungle_slab", + "acacia_slab", + "dark_oak_slab", + nullptr, + nullptr, + "oak_slab", + "spruce_slab", + "birch_slab", + "jungle_slab", + "acacia_slab", + "dark_oak_slab", +}, +/* 127 */ simple("cocoa"), +/* 128 */ simple("sandstone_stairs"), +/* 129 */ simple("emerald_ore"), +/* 130 */ simple("ender_chest"), +/* 131 */ simple("tripwire_hook"), +/* 132 */ simple("tripwire"), +/* 133 */ simple("emerald_block"), +/* 134 */ simple("spruce_stairs"), +/* 135 */ simple("birch_stairs"), +/* 136 */ simple("jungle_stairs"), +/* 137 */ simple("command_block"), +/* 138 */ simple("beacon"), +/* 139 */ { + "cobblestone_wall", + "mossy_cobblestone_wall", +}, +/* 140 */ simple("flower_pot"), +/* 141 */ simple("carrots"), +/* 142 */ simple("potatoes"), +/* 143 */ {}, +/* 144 */ {}, +/* 145 */ { + "anvil", + "anvil", + "anvil", + "anvil", + "chipped_anvil", + "chipped_anvil", + "chipped_anvil", + "chipped_anvil", + "damaged_anvil", + "damaged_anvil", + "damaged_anvil", + "damaged_anvil", +}, +/* 146 */ simple("trapped_chest"), +/* 147 */ simple("light_weighted_pressure_plate"), +/* 148 */ simple("heavy_weighted_pressure_plate"), +/* 149 */ simple("comparator"), +/* 150 */ simple("comparator"), +/* 151 */ simple("daylight_detector"), +/* 152 */ simple("redstone_block"), +/* 153 */ simple("nether_quartz_ore"), +/* 154 */ simple("hopper"), +/* 155 */ simple("quartz_block"), +/* 156 */ simple("quartz_stairs"), +/* 157 */ simple("activator_rail"), +/* 158 */ simple("dropper"), +/* 159 */ { + "white_terracotta", + "orange_terracotta", + "magenta_terracotta", + "light_blue_terracotta", + "yellow_terracotta", + "lime_terracotta", + "pink_terracotta", + "gray_terracotta", + "light_gray_terracotta", + "cyan_terracotta", + "purple_terracotta", + "blue_terracotta", + "brown_terracotta", + "green_terracotta", + "red_terracotta", + "black_terracotta", +}, +/* 160 */ { + "white_stained_glass_pane", + "orange_stained_glass_pane", + "magenta_stained_glass_pane", + "light_blue_stained_glass_pane", + "yellow_stained_glass_pane", + "lime_stained_glass_pane", + "pink_stained_glass_pane", + "gray_stained_glass_pane", + "light_gray_stained_glass_pane", + "cyan_stained_glass_pane", + "purple_stained_glass_pane", + "blue_stained_glass_pane", + "brown_stained_glass_pane", + "green_stained_glass_pane", + "red_stained_glass_pane", + "black_stained_glass_pane", +}, +/* 161 */ { + "acacia_leaves", + "dark_oak_leaves", + nullptr, + nullptr, + "acacia_leaves", + "dark_oak_leaves", + nullptr, + nullptr, + "acacia_leaves", + "dark_oak_leaves", + nullptr, + nullptr, + "acacia_leaves", + "dark_oak_leaves", +}, +/* 162 */ { + "acacia_log", + "dark_oak_log", + nullptr, + nullptr, + "acacia_log", + "dark_oak_log", + nullptr, + nullptr, + "acacia_log", + "dark_oak_log", + nullptr, + nullptr, + "acacia_log", + "dark_oak_log", +}, +/* 163 */ simple("acacia_stairs"), +/* 164 */ simple("dark_oak_stairs"), +/* 165 */ simple("slime_block"), +/* 166 */ simple("barrier"), +/* 167 */ simple("iron_trapdoor"), +/* 168 */ { + "prismarine", + "prismarine_bricks", + "dark_prismarine", +}, +/* 169 */ simple("sea_lantern"), +/* 170 */ simple("hay_block"), +/* 171 */ { + "white_carpet", + "orange_carpet", + "magenta_carpet", + "light_blue_carpet", + "yellow_carpet", + "lime_carpet", + "pink_carpet", + "gray_carpet", + "light_gray_carpet", + "cyan_carpet", + "purple_carpet", + "blue_carpet", + "brown_carpet", + "green_carpet", + "red_carpet", + "black_carpet", +}, +/* 172 */ simple("terracotta"), +/* 173 */ simple("coal_block"), +/* 174 */ simple("packed_ice"), +/* 175 */ { + "sunflower", + "lilac", + "tall_grass", + "large_fern", + "rose_bush", + "peony", +}, +/* 176 */ {/* banner */}, +/* 177 */ {/* wall banner */}, +/* 178 */ simple("daylight_detector"), +/* 179 */ simple("red_sandstone"), +/* 180 */ simple("red_sandstone_stairs"), +/* 181 */ simple("red_sandstone_slab"), +/* 182 */ simple("red_sandstone_slab"), +/* 183 */ simple("spruce_fence_gate"), +/* 184 */ simple("birch_fence_gate"), +/* 185 */ simple("jungle_fence_gate"), +/* 186 */ simple("dark_oak_fence_gate"), +/* 187 */ simple("acacia_fence_gate"), +/* 188 */ simple("spruce_fence"), +/* 189 */ simple("birch_fence"), +/* 190 */ simple("jungle_fence"), +/* 191 */ simple("dark_oak_fence"), +/* 192 */ simple("acacia_fence"), +/* 193 */ simple("spruce_door"), +/* 194 */ simple("birch_door"), +/* 195 */ simple("jungle_door"), +/* 196 */ simple("acacia_door"), +/* 197 */ simple("dark_oak_door"), +/* 198 */ simple("end_rod"), +/* 199 */ simple("chorus_plant"), +/* 200 */ simple("chorus_flower"), +/* 201 */ simple("purpur_block"), +/* 202 */ simple("purpur_pillar"), +/* 203 */ simple("purpur_stairs"), +/* 204 */ simple("purpur_slab"), +/* 205 */ simple("purpur_slab"), +/* 206 */ simple("end_stone_bricks"), +/* 207 */ simple("beetroots"), +/* 208 */ simple("grass_path"), +/* 209 */ simple("end_gateway"), +/* 210 */ simple("repeating_command_block"), +/* 211 */ simple("chain_command_block"), +/* 212 */ simple("frosted_ice"), +/* 213 */ simple("magma_block"), +/* 214 */ simple("nether_wart_block"), +/* 215 */ simple("red_nether_bricks"), +/* 216 */ simple("bone_block"), +/* 217 */ simple("structure_void"), +/* 218 */ simple("observer"), +/* 219 */ simple("white_shulker_box"), +/* 220 */ simple("orange_shulker_box"), +/* 221 */ simple("magenta_shulker_box"), +/* 222 */ simple("light_blue_shulker_box"), +/* 223 */ simple("yellow_shulker_box"), +/* 224 */ simple("lime_shulker_box"), +/* 225 */ simple("pink_shulker_box"), +/* 226 */ simple("gray_shulker_box"), +/* 227 */ simple("light_gray_shulker_box"), +/* 228 */ simple("cyan_shulker_box"), +/* 229 */ simple("purple_shulker_box"), +/* 230 */ simple("blue_shulker_box"), +/* 231 */ simple("brown_shulker_box"), +/* 232 */ simple("green_shulker_box"), +/* 233 */ simple("red_shulker_box"), +/* 234 */ simple("black_shulker_box"), +/* 235 */ simple("white_glazed_terracotta"), +/* 236 */ simple("orange_glazed_terracotta"), +/* 237 */ simple("magenta_glazed_terracotta"), +/* 238 */ simple("light_blue_glazed_terracotta"), +/* 239 */ simple("yellow_glazed_terracotta"), +/* 240 */ simple("lime_glazed_terracotta"), +/* 241 */ simple("pink_glazed_terracotta"), +/* 242 */ simple("gray_glazed_terracotta"), +/* 243 */ simple("light_gray_glazed_terracotta"), +/* 244 */ simple("cyan_glazed_terracotta"), +/* 245 */ simple("purple_glazed_terracotta"), +/* 246 */ simple("blue_glazed_terracotta"), +/* 247 */ simple("brown_glazed_terracotta"), +/* 248 */ simple("green_glazed_terracotta"), +/* 249 */ simple("red_glazed_terracotta"), +/* 250 */ simple("black_glazed_terracotta"), +/* 251 */ { + "white_concrete", + "orange_concrete", + "magenta_concrete", + "light_blue_concrete", + "yellow_concrete", + "lime_concrete", + "pink_concrete", + "gray_concrete", + "light_gray_concrete", + "cyan_concrete", + "purple_concrete", + "blue_concrete", + "brown_concrete", + "green_concrete", + "red_concrete", + "black_concrete", +}, +/* 252 */ { + "white_concrete_powder", + "orange_concrete_powder", + "magenta_concrete_powder", + "light_blue_concrete_powder", + "yellow_concrete_powder", + "lime_concrete_powder", + "pink_concrete_powder", + "gray_concrete_powder", + "light_gray_concrete_powder", + "cyan_concrete_powder", + "purple_concrete_powder", + "blue_concrete_powder", + "brown_concrete_powder", + "green_concrete_powder", + "red_concrete_powder", + "black_concrete_powder", +}, +/* 253 */ {}, +/* 254 */ {}, +/* 255 */ simple("structure_block"), diff --git a/src/UniqueCPtr.hpp b/src/UniqueCPtr.hpp new file mode 100644 index 0000000..9e70b89 --- /dev/null +++ b/src/UniqueCPtr.hpp @@ -0,0 +1,37 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include + + +template class UniqueCPtr : public std::unique_ptr { +public: + UniqueCPtr() : std::unique_ptr(nullptr, std::free) {} + template UniqueCPtr(T2 ptr) : std::unique_ptr(ptr, std::free) {} +}; diff --git a/src/Util.hpp b/src/Util.hpp new file mode 100644 index 0000000..68a83b1 --- /dev/null +++ b/src/Util.hpp @@ -0,0 +1,47 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include +#include +#include + + +namespace MinedMap { + +template static inline T assertValue(T&& val) { + if (!val) + throw std::invalid_argument("assertValue failed"); + + return std::forward(val); +} + +static inline float clamp(float v, float min, float max) { + return std::max(std::min(v, max), min); +} + +} diff --git a/src/World/Block.hpp b/src/World/Block.hpp new file mode 100644 index 0000000..30ed186 --- /dev/null +++ b/src/World/Block.hpp @@ -0,0 +1,59 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "../NBT/CompoundTag.hpp" +#include "../Resource/Biome.hpp" +#include "../Resource/BlockType.hpp" + + +namespace MinedMap { +namespace World { + +struct Block { + const Resource::BlockType *type; + unsigned depth; + uint8_t blockLight; + + bool isVisible() const { + return type && (type->flags & BLOCK_OPAQUE); + } + + Resource::FloatColor getColor(uint8_t biome) const { + if (!isVisible()) + return Resource::FloatColor {}; + + return (Resource::BIOMES[biome] ?: Resource::BIOME_DEFAULT)->getBlockColor(type, depth); + } + + operator bool() const { + return type; + } +}; + +} +} diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp new file mode 100644 index 0000000..423d7e8 --- /dev/null +++ b/src/World/Chunk.cpp @@ -0,0 +1,159 @@ +/* + Copyright (c) 2015-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Chunk.hpp" +#include "../NBT/IntTag.hpp" +#include "../NBT/ListTag.hpp" +#include "../NBT/StringTag.hpp" + +#include +#include + + +namespace MinedMap { +namespace World { + +Chunk::Chunk(const ChunkData *data) { + level = assertValue(data->getRoot().get("Level")); + + std::shared_ptr sectionsTag = level->get("Sections"); + if (!sectionsTag || sectionsTag->empty()) + return; + + auto biomesIntArray = level->get("Biomes"); + auto biomesByteArray = level->get("Biomes"); + + if (biomesIntArray && biomesIntArray->getLength() == BSIZE*BSIZE*BMAXY) + biomeInts = std::move(biomesIntArray); + else if (biomesIntArray && biomesIntArray->getLength() == SIZE*SIZE) + biomeIntsPre115 = std::move(biomesIntArray); + else if (biomesByteArray && biomesByteArray->getLength() == SIZE*SIZE) + biomeBytes = std::move(biomesByteArray); + else + throw std::invalid_argument("corrupt biome data"); + + auto dataVersionTag = data->getRoot().get("DataVersion"); + uint32_t dataVersion = dataVersionTag ? dataVersionTag->getValue() : 0; + + for (auto &sTag : *sectionsTag) { + auto s = std::dynamic_pointer_cast(sTag); + std::unique_ptr

section = Section::makeSection(s, dataVersion); + size_t Y = section->getY(); + sections.resize(Y); + sections.push_back(std::move(section)); + } +} + +uint8_t Chunk::getBiome(size_t x, size_t y, size_t z) const { + if (x > SIZE || y > MAXY || z > SIZE) + throw std::invalid_argument("corrupt chunk data"); + + if (biomeInts) + return biomeInts->getValue((y/BGROUP)*BSIZE*BSIZE + (z/BGROUP)*BSIZE + (x/BGROUP)); + else if (biomeIntsPre115) + return biomeIntsPre115->getValue(z*SIZE + x); + else if (biomeBytes) + return biomeBytes->getValue(z*SIZE + x); + else + return 0xff; +} + +Block Chunk::getBlock(size_t x, Chunk::Height height, size_t z) const { + Block block = {}; + + block.depth = height.depth; + + size_t Y = height.y / SIZE; + size_t y = height.y % SIZE; + + if (Y < sections.size() && sections[Y]) + block.type = sections[Y]->getBlockStateAt(x, y, z); + + size_t Yt = (height.y + 1) / SIZE; + size_t yt = (height.y + 1) % SIZE; + + if (Yt < sections.size() && sections[Yt]) + block.blockLight = sections[Yt]->getBlockLightAt(x, yt, z); + + return block; +} + +bool Chunk::getHeight(Chunk::Height *height, const Section *section, size_t x, size_t y, size_t z, bool withDepth) const { + if (height->depth > 0) + return false; + + if (!withDepth && height->y > 0) + return false; + + const Resource::BlockType *type = section->getBlockStateAt(x, y, z); + if (!type || !(type->flags & BLOCK_OPAQUE)) + return false; + + if (height->y == 0) + height->y = SIZE*section->getY() + y; + + if (!withDepth) + return true; + + if (type->flags & BLOCK_WATER) + return false; + + height->depth = SIZE*section->getY() + y; + + return true; +} + +Chunk::Heightmap Chunk::getTopLayer(bool withDepth) const { + size_t done = 0; + Heightmap ret = {}; + + for (ssize_t Y = sections.size() - 1; Y >= 0; Y--) { + if (done == SIZE*SIZE) + break; + + if (!sections[Y]) + continue; + + const Section *section = sections[Y].get(); + + for (ssize_t y = SIZE-1; y >= 0; y--) { + if (done == SIZE*SIZE) + break; + + for (size_t z = 0; z < SIZE; z++) { + for (size_t x = 0; x < SIZE; x++) { + if (getHeight(&ret.v[x][z], section, x, y, z, withDepth)) + done++; + } + } + } + } + + return ret; +} + +} +} diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp new file mode 100644 index 0000000..ccbba54 --- /dev/null +++ b/src/World/Chunk.hpp @@ -0,0 +1,96 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + + +#include "Block.hpp" +#include "ChunkData.hpp" +#include "Section.hpp" +#include "../NBT/ByteArrayTag.hpp" +#include "../NBT/IntArrayTag.hpp" +#include "../Resource/BlockType.hpp" +#include "../Util.hpp" + +#include + + +namespace MinedMap { +namespace World { + +class Chunk { +public: + static const size_t SIZE = Section::SIZE; + static const size_t MAXY = 256; + + static const size_t BGROUP = 4; + static const size_t BSIZE = SIZE / BGROUP; + static const size_t BMAXY = MAXY / BGROUP; + + struct Height { + unsigned y; + unsigned depth; + }; + + struct Heightmap { + Height v[SIZE][SIZE]; + }; + +private: + std::shared_ptr level; + std::vector> sections; + + std::shared_ptr biomeBytes; + std::shared_ptr biomeIntsPre115; + std::shared_ptr biomeInts; + + bool getHeight(Height *height, const Section *section, size_t x, size_t y, size_t z, bool withDepth) const; + + const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const { + size_t Y = y / SIZE; + + if (Y >= sections.size() || !sections[Y]) + return nullptr; + + return sections[Y]->getBlockStateAt(x, y % SIZE, z); + } + + +public: + Chunk(const ChunkData *data); + + const NBT::CompoundTag & getLevel() const { + return *level; + } + + uint8_t getBiome(size_t x, size_t y, size_t z) const; + Block getBlock(size_t x, Height y, size_t z) const; + + Heightmap getTopLayer(bool withDepth) const; +}; + +} +} diff --git a/src/World/ChunkData.cpp b/src/World/ChunkData.cpp new file mode 100644 index 0000000..6cb73b5 --- /dev/null +++ b/src/World/ChunkData.cpp @@ -0,0 +1,97 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "ChunkData.hpp" + +#include +#include +#include + +#include + + +namespace MinedMap { +namespace World { + +ChunkData::ChunkData(Buffer buffer) { + size_t size = buffer.get32(); + + Buffer buffer2(buffer.get(size), size); + + uint8_t format = buffer2.get8(); + if (format != 2) + throw std::invalid_argument("unknown chunk format"); + + inflateChunk(buffer2); + parseChunk(); +} + +void ChunkData::inflateChunk(Buffer buffer) { + size_t outlen = 0; + uint8_t *output = nullptr; + + z_stream stream = {}; + int ret = inflateInit(&stream); + if (ret != Z_OK) + throw std::runtime_error("inflateInit() failed"); + + stream.avail_in = buffer.getRemaining(); + stream.next_in = const_cast(buffer.get(stream.avail_in)); + + while (stream.avail_in) { + outlen += 65536; + output = static_cast(std::realloc(output, outlen)); + + stream.next_out = output + stream.total_out; + stream.avail_out = outlen - stream.total_out; + + ret = inflate(&stream, Z_NO_FLUSH); + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&stream); + throw std::runtime_error("inflate() failed"); + } + } + + inflateEnd(&stream); + + len = stream.total_out; + data = UniqueCPtr(output); +} + +void ChunkData::parseChunk() { + Buffer nbt(data.get(), len); + std::pair> tag = NBT::Tag::readNamedTag(&nbt); + if (!tag.first.empty()) + throw std::invalid_argument("invalid root tag"); + + root = assertValue(std::dynamic_pointer_cast(tag.second)); +} + +} +} diff --git a/src/World/ChunkData.hpp b/src/World/ChunkData.hpp new file mode 100644 index 0000000..5fe27c9 --- /dev/null +++ b/src/World/ChunkData.hpp @@ -0,0 +1,60 @@ +/* + Copyright (c) 2015-2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + + +#include "../Buffer.hpp" +#include "../UniqueCPtr.hpp" +#include "../Util.hpp" +#include "../NBT/CompoundTag.hpp" + +#include + + +namespace MinedMap { +namespace World { + +class ChunkData { +private: + size_t len; + UniqueCPtr data; + + std::shared_ptr root; + + void inflateChunk(Buffer buffer); + void parseChunk(); + +public: + ChunkData(Buffer buffer); + + const NBT::CompoundTag & getRoot() const { + return *root; + } +}; + +} +} diff --git a/src/World/Level.cpp b/src/World/Level.cpp new file mode 100644 index 0000000..56628b9 --- /dev/null +++ b/src/World/Level.cpp @@ -0,0 +1,56 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Level.hpp" +#include "../GZip.hpp" +#include "../Util.hpp" +#include "../NBT/IntTag.hpp" + + +namespace MinedMap { +namespace World { + +Level::Level(const char *filename) { + buffer = readGZip(filename); + + Buffer nbt(buffer.data(), buffer.size()); + std::pair> tag = NBT::Tag::readNamedTag(&nbt); + if (tag.first != "") + throw std::invalid_argument("invalid root tag"); + + root = assertValue(std::dynamic_pointer_cast(tag.second)); + data = assertValue(root->get("Data")); +} + +std::pair Level::getSpawn() const { + int32_t x = assertValue(data->get("SpawnX"))->getValue(); + int32_t z = assertValue(data->get("SpawnZ"))->getValue(); + + return std::make_pair(x, z); +} + +} +} diff --git a/src/World/Level.hpp b/src/World/Level.hpp new file mode 100644 index 0000000..6fd45a8 --- /dev/null +++ b/src/World/Level.hpp @@ -0,0 +1,52 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "../NBT/CompoundTag.hpp" + +#include +#include + + +namespace MinedMap { +namespace World { + +class Level { +private: + std::vector buffer; + + std::shared_ptr root; + std::shared_ptr data; + +public: + Level(const char *filename); + + std::pair getSpawn() const; +}; + +} +} diff --git a/src/World/Region.cpp b/src/World/Region.cpp new file mode 100644 index 0000000..a813247 --- /dev/null +++ b/src/World/Region.cpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Region.hpp" + +#include +#include +#include + + +namespace MinedMap { +namespace World { + +Region::ChunkMap Region::processHeader(const uint8_t header[4096]) { + ChunkMap map; + + for (size_t z = 0; z < 32; z++) { + for (size_t x = 0; x < 32; x++) { + const uint8_t *p = &header[128*z + x*4]; + + size_t offset = (p[0] << 16) | (p[1] << 8) | p[2]; + + if (!offset) + continue; + + size_t len = p[3]; + + map.emplace(offset, ChunkDesc(x, z, len)); + } + } + + return map; +} + +void Region::visitChunks(const char *filename, const ChunkVisitor &visitor) { + std::ifstream file; + file.exceptions(std::ios::badbit); + file.open(filename, std::ios::in | std::ios::binary); + + ChunkMap chunkMap; + + { + uint8_t header[4096]; + file.read((char *)header, sizeof(header)); + + chunkMap = processHeader(header); + } + + bool seen[SIZE][SIZE] = {}; + + size_t i = 1, c = 0; + while (!file.eof() && !file.fail()) { + auto it = chunkMap.find(i); + if (it == chunkMap.end()) { + file.ignore(4096); + i++; + continue; + } + + size_t x, z, len; + std::tie(x, z, len) = it->second; + + if (seen[x][z]) + throw std::invalid_argument("duplicate chunk"); + + seen[x][z] = true; + c++; + + uint8_t buffer[len * 4096]; + std::memset(buffer, 0, sizeof(buffer)); + file.read((char *)buffer, len * 4096); + + ChunkData chunk(Buffer(buffer, len * 4096)); + visitor(x, z, &chunk); + + i += len; + } + + if (c != chunkMap.size()) + throw std::invalid_argument("region incomplete"); +} + +} +} diff --git a/src/World/Region.hpp b/src/World/Region.hpp new file mode 100644 index 0000000..00bfd7b --- /dev/null +++ b/src/World/Region.hpp @@ -0,0 +1,60 @@ +/* + Copyright (c) 2015, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + +#include "Chunk.hpp" + +#include +#include +#include +#include +#include + + +namespace MinedMap { +namespace World { + +class Region { +public: + static const size_t SIZE = 32; + + typedef std::function ChunkVisitor; + + Region() = delete; + +private: + typedef std::tuple ChunkDesc; + typedef std::unordered_map ChunkMap; + + static ChunkMap processHeader(const uint8_t header[4096]); + +public: + static void visitChunks(const char *filename, const ChunkVisitor &visitor); +}; + +} +} diff --git a/src/World/Section.cpp b/src/World/Section.cpp new file mode 100644 index 0000000..23b0ebf --- /dev/null +++ b/src/World/Section.cpp @@ -0,0 +1,148 @@ +/* + Copyright (c) 2015-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Section.hpp" +#include "../NBT/ByteTag.hpp" +#include "../NBT/StringTag.hpp" +#include "../Util.hpp" + +#include + + +namespace MinedMap { +namespace World { + +Section::Section(const std::shared_ptr §ion) { + Y = assertValue(section->get("Y"))->getValue(); + blockLight = section->get("BlockLight"); +} + +const Resource::BlockType * Section::getBlockStateAt(size_t, size_t, size_t) const { + return nullptr; +} + +std::unique_ptr
Section::makeSection(const std::shared_ptr §ion, uint32_t dataVersion) { + std::shared_ptr blockStates = section->get("BlockStates"); + if (blockStates) { + const std::shared_ptr palette = assertValue(section->get("Palette")); + + return std::unique_ptr
(new PaletteSection(section, std::move(blockStates), palette, dataVersion)); + } + + std::shared_ptr blocks = section->get("Blocks"); + if (blocks) { + std::shared_ptr data = assertValue(section->get("Data")); + + return std::unique_ptr
(new LegacySection(section, std::move(blocks), std::move(data))); + } + + return std::unique_ptr
(new Section(section)); +} + + +const Resource::BlockType * LegacySection::getBlockStateAt(size_t x, size_t y, size_t z) const { + uint8_t type = getBlockAt(x, y, z); + uint8_t data = getDataAt(x, y, z); + + return Resource::LEGACY_BLOCK_TYPES.types[type][data]; +} + + +const Resource::BlockType * PaletteSection::lookup(const std::string &name, uint32_t dataVersion) { + if (dataVersion < 1900 && name == "minecraft:stone_slab") + return Resource::BlockType::lookup("minecraft:smooth_stone_slab"); + + return Resource::BlockType::lookup(name); +} + +PaletteSection::PaletteSection( + const std::shared_ptr §ion, + std::shared_ptr &&blockStates0, + const std::shared_ptr &paletteData, + uint32_t dataVersion0 +) : Section(section), blockStates(blockStates0), dataVersion(dataVersion0) { + bits = 4; + while ((1u << bits) < paletteData->size()) { + bits++; + + if (bits > 12) + throw std::invalid_argument("unsupported block palette size"); + } + + unsigned expectedLength; + + if (dataVersion < 2529) { + expectedLength = 64 * bits; + } else { + unsigned blocksPerWord = (64 / bits); + expectedLength = (4096 + blocksPerWord - 1) / blocksPerWord; + } + + if (blockStates->getLength() != expectedLength) + throw std::invalid_argument("corrupt section data"); + + for (const auto &entry : *paletteData) { + const NBT::CompoundTag &paletteEntry = *assertValue(dynamic_cast(entry.get())); + std::string name = assertValue(paletteEntry.get("Name"))->getValue(); + + const Resource::BlockType *type = lookup(name, dataVersion); + if (!type) + std::fprintf(stderr, "Warning: unknown block type: %s\n", name.c_str()); + + palette.push_back(type); + } +} + +const Resource::BlockType * PaletteSection::getBlockStateAt(size_t x, size_t y, size_t z) const { + size_t index = getIndex(x, y, z); + size_t bitIndex; + + if (dataVersion < 2529) { + bitIndex = bits * index; + } else { + unsigned blocksPerWord = (64 / bits); + size_t word = index / blocksPerWord; + bitIndex = 64 * word + bits * (index % blocksPerWord); + } + + size_t pos = bitIndex >> 3; + size_t shift = bitIndex & 7; + uint16_t mask = (1u << bits) - 1; + + uint32_t v = blockStates->getPointer()[mangleByteIndex(pos)]; + + if (shift + bits > 8) + v |= blockStates->getPointer()[mangleByteIndex(pos + 1)] << 8; + if (shift + bits > 16) + v |= blockStates->getPointer()[mangleByteIndex(pos + 2)] << 16; + /* We do not need to check for shift+bits > 24: bits should never + be greater than 12, so our value will never span more than 3 bytes */ + + return palette.at((v >> shift) & mask); +} + +} +} diff --git a/src/World/Section.hpp b/src/World/Section.hpp new file mode 100644 index 0000000..7e90acb --- /dev/null +++ b/src/World/Section.hpp @@ -0,0 +1,137 @@ +/* + Copyright (c) 2015-2019, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#pragma once + + +#include "../NBT/ByteArrayTag.hpp" +#include "../NBT/CompoundTag.hpp" +#include "../NBT/ListTag.hpp" +#include "../NBT/LongArrayTag.hpp" +#include "../Resource/BlockType.hpp" + +#include +#include + + +namespace MinedMap { +namespace World { + +class Section { +public: + static const size_t SIZE = 16; + +private: + size_t Y; + std::shared_ptr blockLight; + +protected: + static size_t getIndex(size_t x, size_t y, size_t z) { + if (x >= SIZE || y >= SIZE || z >= SIZE) + throw std::range_error("Chunk::getIndex(): bad coordinates"); + + return SIZE*SIZE*y + SIZE*z + x; + } + + static uint8_t getHalf(const uint8_t *v, size_t x, size_t y, size_t z) { + size_t i = getIndex(x, y, z); + + if (i % 2) + return (v[i/2] >> 4); + else + return (v[i/2] & 0xf); + } + + Section(const std::shared_ptr §ion); + +public: + virtual ~Section() {} + + size_t getY() const { return Y; }; + + virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const; + + uint8_t getBlockLightAt(size_t x, size_t y, size_t z) const { + if (!blockLight) + return 0; + + return getHalf(blockLight->getPointer(), x, y, z); + } + + static std::unique_ptr
makeSection(const std::shared_ptr §ion, uint32_t dataVersion); +}; + +class LegacySection : public Section { +private: + std::shared_ptr blocks; + std::shared_ptr data; + + + uint8_t getBlockAt(size_t x, size_t y, size_t z) const { + return blocks->getValue(getIndex(x, y, z)); + } + + uint8_t getDataAt(size_t x, size_t y, size_t z) const { + return getHalf(data->getPointer(), x, y, z); + } + +public: + LegacySection( + const std::shared_ptr §ion, + std::shared_ptr &&blocks0, + std::shared_ptr &&data0 + ) : Section(section), blocks(blocks0), data(data0) {} + + virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const; +}; + +class PaletteSection : public Section { +private: + std::shared_ptr blockStates; + std::vector palette; + uint32_t dataVersion; + unsigned bits; + + + static const Resource::BlockType * lookup(const std::string &name, uint32_t dataVersion); + + static size_t mangleByteIndex(size_t index) { + return (index & ~(size_t)7) + 7 - (index & 7); + } + +public: + PaletteSection( + const std::shared_ptr §ion, + std::shared_ptr &&blockStates0, + const std::shared_ptr &paletteData, + uint32_t dataVersion0 + ); + + virtual const Resource::BlockType * getBlockStateAt(size_t x, size_t y, size_t z) const; +}; + +} +} diff --git a/src/core/common.rs b/src/core/common.rs deleted file mode 100644 index 094d567..0000000 --- a/src/core/common.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! Common data types and functions used by multiple generation steps - -use std::{ - collections::{BTreeMap, BTreeSet}, - fmt::Debug, - hash::Hash, - path::{Path, PathBuf}, -}; - -use anyhow::{Context, Result}; -use bincode::{Decode, Encode}; -use clap::ValueEnum; -use regex::{Regex, RegexSet}; -use serde::Serialize; - -use crate::{ - io::fs::FileMetaVersion, - resource::Biome, - types::*, - world::{block_entity::BlockEntity, layer}, -}; - -// Increase to force regeneration of all output files - -/// MinedMap processed region data version number -/// -/// Increase when the generation of processed regions from region data changes -/// (usually because of updated resource data) -pub const REGION_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(8); - -/// MinedMap map tile data version number -/// -/// Increase when the generation of map tiles from processed regions changes -/// (because of code changes in tile generation) -pub const MAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0); - -/// MinedMap lightmap data version number -/// -/// Increase when the generation of lightmap tiles from region data changes -/// (usually because of updated resource data) -pub const LIGHTMAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(6); - -/// MinedMap mipmap data version number -/// -/// Increase when the mipmap generation changes (this should not happen) -pub const MIPMAP_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(0); - -/// MinedMap processed entity data version number -/// -/// Increase when entity collection changes bacause of code changes. -pub const ENTITIES_FILE_META_VERSION: FileMetaVersion = FileMetaVersion(3); - -/// Coordinate pair of a generated tile -/// -/// Each tile corresponds to one Minecraft region file -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct TileCoords { - /// The X coordinate - pub x: i32, - /// The Z coordinate - pub z: i32, -} - -impl Debug for TileCoords { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "({}, {})", self.x, self.z) - } -} - -/// Set of tile coordinates -/// -/// Used to store list of populated tiles for each mipmap level in the -/// viewer metadata file. -#[derive(Debug, Clone, Default, Serialize)] -#[serde(transparent)] -pub struct TileCoordMap(pub BTreeMap>); - -impl TileCoordMap { - /// Checks whether the map contains a given coordinate pair - pub fn contains(&self, coords: TileCoords) -> bool { - let Some(xs) = self.0.get(&coords.z) else { - return false; - }; - - xs.contains(&coords.x) - } -} - -/// Data structure for storing chunk data between processing and rendering steps -#[derive(Debug, Encode, Decode)] -pub struct ProcessedChunk { - /// Block type data - pub blocks: Box, - /// Biome data - pub biomes: Box, - /// Block height/depth data - pub depths: Box, -} - -/// Data structure for storing region data between processing and rendering steps -#[derive(Debug, Default, Encode, Decode)] -pub struct ProcessedRegion { - /// List of biomes used in the region - /// - /// Indexed by [ProcessedChunk] biome data - pub biome_list: Vec, - /// Processed chunk data - pub chunks: ChunkArray>>, -} - -/// Data structure for storing entity data between processing and collection steps -#[derive(Debug, Default, Encode, Decode)] -pub struct ProcessedEntities { - /// List of block entities - pub block_entities: Vec, -} - -/// Derives a filename from region coordinates and a file extension -/// -/// Can be used for input regions, processed data or rendered tiles -fn coord_filename(coords: TileCoords, ext: &str) -> String { - format!("r.{}.{}.{}", coords.x, coords.z, ext) -} - -/// Tile kind corresponding to a map layer -#[derive(Debug, Clone, Copy)] -pub enum TileKind { - /// Regular map tile contains block colors - Map, - /// Lightmap tile for illumination layer - Lightmap, -} - -/// Common configuration based on command line arguments -#[derive(Debug)] -pub struct Config { - /// Number of threads for parallel processing - pub num_threads: usize, - /// Number of threads for initial parallel processing - pub num_threads_initial: usize, - /// Path of input region directory - pub region_dir: PathBuf, - /// Path of input `level.dat` file - pub level_dat_path: PathBuf, - /// Path of input `level.dat_old` file - pub level_dat_old_path: PathBuf, - /// Base path for storage of rendered tile data - pub output_dir: PathBuf, - /// Path for storage of intermediate processed data files - pub processed_dir: PathBuf, - /// Path for storage of processed entity data files - pub entities_dir: PathBuf, - /// Path for storage of the final merged processed entity data file - pub entities_path_final: PathBuf, - /// Path of viewer metadata file - pub viewer_info_path: PathBuf, - /// Path of viewer entities file - pub viewer_entities_path: PathBuf, - /// Format of generated map tiles - pub image_format: ImageFormat, - /// Sign text filter patterns - pub sign_patterns: RegexSet, - /// Sign text transformation pattern - pub sign_transforms: Vec<(Regex, String)>, -} - -impl Config { - /// Crates a new [Config] from [command line arguments](super::Args) - pub fn new(args: &super::Args) -> Result { - let num_threads = match args.jobs { - Some(0) => num_cpus::get(), - Some(threads) => threads, - None => 1, - }; - let num_threads_initial = args.jobs_initial.unwrap_or(num_threads); - - let region_dir = [&args.input_dir, Path::new("region")].iter().collect(); - let level_dat_path = [&args.input_dir, Path::new("level.dat")].iter().collect(); - let level_dat_old_path = [&args.input_dir, Path::new("level.dat_old")] - .iter() - .collect(); - let processed_dir: PathBuf = [&args.output_dir, Path::new("processed")].iter().collect(); - let entities_dir: PathBuf = [&processed_dir, Path::new("entities")].iter().collect(); - let entities_path_final = [&entities_dir, Path::new("entities.bin")].iter().collect(); - let viewer_info_path = [&args.output_dir, Path::new("info.json")].iter().collect(); - let viewer_entities_path = [&args.output_dir, Path::new("entities.json")] - .iter() - .collect(); - - let sign_patterns = Self::sign_patterns(args).context("Failed to parse sign patterns")?; - let sign_transforms = - Self::sign_transforms(args).context("Failed to parse sign transforms")?; - - Ok(Config { - num_threads, - num_threads_initial, - region_dir, - level_dat_path, - level_dat_old_path, - output_dir: args.output_dir.clone(), - processed_dir, - entities_dir, - entities_path_final, - viewer_info_path, - viewer_entities_path, - image_format: args.image_format, - sign_patterns, - sign_transforms, - }) - } - - /// Parses the sign prefixes and sign filters into a [RegexSet] - fn sign_patterns(args: &super::Args) -> Result { - let prefix_patterns: Vec<_> = args - .sign_prefix - .iter() - .map(|prefix| format!("^{}", regex::escape(prefix))) - .collect(); - Ok(RegexSet::new( - prefix_patterns.iter().chain(args.sign_filter.iter()), - )?) - } - - /// Parses the sign transform argument into a vector of [Regex] and - /// corresponding replacement strings - fn sign_transforms(args: &super::Args) -> Result> { - let splitter = Regex::new(r"^s/((?:[^\\/]|\\.)*)/((?:[^\\/]|\\.)*)/$").unwrap(); - - args.sign_transform - .iter() - .map(|t| Self::sign_transform(&splitter, t)) - .collect() - } - - /// Parses the sign transform argument into a [Regex] and its corresponding - /// replacement string - fn sign_transform(splitter: &Regex, transform: &str) -> Result<(Regex, String)> { - let captures = splitter - .captures(transform) - .with_context(|| format!("Invalid transform pattern '{transform}'"))?; - let regexp = Regex::new(&captures[1])?; - let replacement = captures[2].to_string(); - Ok((regexp, replacement)) - } - - /// Constructs the path to an input region file - pub fn region_path(&self, coords: TileCoords) -> PathBuf { - let filename = coord_filename(coords, "mca"); - [&self.region_dir, Path::new(&filename)].iter().collect() - } - - /// Constructs the path of an intermediate processed region file - pub fn processed_path(&self, coords: TileCoords) -> PathBuf { - let filename = coord_filename(coords, "bin"); - [&self.processed_dir, Path::new(&filename)].iter().collect() - } - - /// Constructs the base output path for processed entity data - pub fn entities_dir(&self, level: usize) -> PathBuf { - [&self.entities_dir, Path::new(&level.to_string())] - .iter() - .collect() - } - - /// Constructs the path of a processed entity data file - pub fn entities_path(&self, level: usize, coords: TileCoords) -> PathBuf { - let filename = coord_filename(coords, "bin"); - let dir = self.entities_dir(level); - [Path::new(&dir), Path::new(&filename)].iter().collect() - } - - /// Constructs the base output path for a [TileKind] and mipmap level - pub fn tile_dir(&self, kind: TileKind, level: usize) -> PathBuf { - let prefix = match kind { - TileKind::Map => "map", - TileKind::Lightmap => "light", - }; - let dir = format!("{prefix}/{level}"); - [&self.output_dir, Path::new(&dir)].iter().collect() - } - - /// Returns the file extension for the configured image format - pub fn tile_extension(&self) -> &'static str { - match self.image_format { - ImageFormat::Png => "png", - ImageFormat::Webp => "webp", - } - } - /// Returns the configurured image format for the image library - pub fn tile_image_format(&self) -> image::ImageFormat { - match self.image_format { - ImageFormat::Png => image::ImageFormat::Png, - ImageFormat::Webp => image::ImageFormat::WebP, - } - } - - /// Constructs the path of an output tile image - pub fn tile_path(&self, kind: TileKind, level: usize, coords: TileCoords) -> PathBuf { - let filename = coord_filename(coords, self.tile_extension()); - let dir = self.tile_dir(kind, level); - [Path::new(&dir), Path::new(&filename)].iter().collect() - } -} - -/// Format of generated map tiles -#[derive(Debug, Clone, Copy, Default, ValueEnum)] -pub enum ImageFormat { - /// Generate PNG images - #[default] - Png, - /// Generate WebP images - Webp, -} - -/// Copies a chunk image into a region tile -pub fn overlay_chunk(image: &mut I, chunk: &J, coords: ChunkCoords) -where - I: image::GenericImage, - J: image::GenericImageView, -{ - image::imageops::overlay( - image, - chunk, - coords.x.0 as i64 * BLOCKS_PER_CHUNK as i64, - coords.z.0 as i64 * BLOCKS_PER_CHUNK as i64, - ); -} diff --git a/src/core/entity_collector.rs b/src/core/entity_collector.rs deleted file mode 100644 index 0d18090..0000000 --- a/src/core/entity_collector.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! The [EntityCollector] - -use std::path::Path; - -use anyhow::{Context, Result}; -use tracing::{info, warn}; - -use super::{common::*, tile_collector::TileCollector, tile_merger::TileMerger}; -use crate::io::{fs, storage}; - -/// Generates mipmap tiles from full-resolution tile images -pub struct EntityCollector<'a> { - /// Common MinedMap configuration from command line - config: &'a Config, - /// List of populated tiles for base mipmap level (level 0) - regions: &'a [TileCoords], -} - -impl TileMerger for EntityCollector<'_> { - fn file_meta_version(&self) -> fs::FileMetaVersion { - ENTITIES_FILE_META_VERSION - } - - fn tile_path(&self, level: usize, coords: TileCoords) -> std::path::PathBuf { - self.config.entities_path(level, coords) - } - - fn write_tile( - &self, - file: &mut std::io::BufWriter, - sources: &[super::tile_merger::Source], - ) -> Result<()> { - Self::merge_entity_lists(file, sources.iter().map(|source| &source.1)) - } -} - -impl TileCollector for EntityCollector<'_> { - type CollectOutput = (); - - fn tiles(&self) -> &[TileCoords] { - self.regions - } - - fn prepare(&self, level: usize) -> Result<()> { - fs::create_dir_all(&self.config.entities_dir(level)) - } - - fn finish( - &self, - _level: usize, - _outputs: impl Iterator, - ) -> Result<()> { - Ok(()) - } - - fn collect_one( - &self, - level: usize, - coords: TileCoords, - prev: &TileCoordMap, - ) -> Result { - self.merge_tiles(level, coords, prev)?; - Ok(()) - } -} - -impl<'a> EntityCollector<'a> { - /// Constructs a new EntityCollector - pub fn new(config: &'a Config, regions: &'a [TileCoords]) -> Self { - EntityCollector { config, regions } - } - - /// Merges multiple entity lists into one - fn merge_entity_lists>( - file: &mut std::io::BufWriter, - sources: impl Iterator, - ) -> Result<()> { - let mut output = ProcessedEntities::default(); - - for source_path in sources { - let mut source: ProcessedEntities = match storage::read_file(source_path.as_ref()) { - Ok(source) => source, - Err(err) => { - warn!( - "Failed to read entity data file {}: {:?}", - source_path.as_ref().display(), - err, - ); - continue; - } - }; - - output.block_entities.append(&mut source.block_entities); - } - - storage::write(file, &output).context("Failed to write entity data") - } - - /// Runs the mipmap generation - pub fn run(self) -> Result<()> { - info!("Collecting entity data..."); - - let tile_stack = self.collect_tiles()?; - - // Final merge - let level = tile_stack.len() - 1; - let tile_map = &tile_stack[level]; - let sources: Vec<_> = [(-1, -1), (-1, 0), (0, -1), (0, 0)] - .into_iter() - .map(|(x, z)| TileCoords { x, z }) - .filter(|&coords| tile_map.contains(coords)) - .map(|coords| self.tile_path(level, coords)) - .collect(); - - fs::create_with_tmpfile(&self.config.entities_path_final, |file| { - Self::merge_entity_lists(file, sources.iter()) - })?; - - info!("Collected entity data."); - Ok(()) - } -} diff --git a/src/core/metadata_writer.rs b/src/core/metadata_writer.rs deleted file mode 100644 index 40c5796..0000000 --- a/src/core/metadata_writer.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! The [MetadataWriter] and related types - -use anyhow::{Context, Result}; -use regex::Regex; -use serde::Serialize; - -use crate::{ - core::common::*, - io::{fs, storage}, - world::{ - block_entity::{self, BlockEntity, BlockEntityData}, - de, sign, - }, -}; - -/// Minimum and maximum X and Z tile coordinates for a mipmap level -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -struct Bounds { - /// Minimum X coordinate - min_x: i32, - /// Maximum X coordinate - max_x: i32, - /// Minimum Z coordinate - min_z: i32, - /// Maximum Z coordinate - max_z: i32, -} - -/// Mipmap level information in viewer metadata file -#[derive(Debug, Serialize)] -struct Mipmap<'t> { - /// Minimum and maximum tile coordinates of the mipmap level - bounds: Bounds, - /// Map of populated tiles for the mipmap level - regions: &'t TileCoordMap, -} - -/// Initial spawn point for new players -#[derive(Debug, Serialize)] -struct Spawn { - /// Spawn X coordinate - x: i32, - /// Spawn Z coordinate - z: i32, -} - -/// Keeps track of enabled MinedMap features -#[derive(Debug, Serialize)] -struct Features { - /// Sign layer - signs: bool, -} - -/// Viewer metadata JSON data structure -#[derive(Debug, Serialize)] -struct Metadata<'t> { - /// Tile information for each mipmap level - mipmaps: Vec>, - /// Initial spawn point for new players - spawn: Spawn, - /// Enabled MinedMap features - features: Features, - /// Format of generated map tiles - tile_extension: &'static str, -} - -/// Viewer entity JSON data structure -#[derive(Debug, Serialize, Default)] -struct Entities { - /// List of signs - signs: Vec, -} - -/// The MetadataWriter is used to generate the viewer metadata file -pub struct MetadataWriter<'a> { - /// Common MinedMap configuration from command line - config: &'a Config, - /// Map of generated tiles for each mipmap level - tiles: &'a [TileCoordMap], -} - -impl<'a> MetadataWriter<'a> { - /// Creates a new MetadataWriter - pub fn new(config: &'a Config, tiles: &'a [TileCoordMap]) -> Self { - MetadataWriter { config, tiles } - } - - /// Helper to construct a [Mipmap] data structure from a [TileCoordMap] - fn mipmap_entry(regions: &TileCoordMap) -> Mipmap { - let mut min_x = i32::MAX; - let mut max_x = i32::MIN; - let mut min_z = i32::MAX; - let mut max_z = i32::MIN; - - for (&z, xs) in ®ions.0 { - if z < min_z { - min_z = z; - } - if z > max_z { - max_z = z; - } - - for &x in xs { - if x < min_x { - min_x = x; - } - if x > max_x { - max_x = x; - } - } - } - - Mipmap { - bounds: Bounds { - min_x, - max_x, - min_z, - max_z, - }, - regions, - } - } - - /// Reads and deserializes the `level.dat` of the Minecraft save data - fn read_level_dat(&self) -> Result { - let res = crate::nbt::data::from_file(&self.config.level_dat_path); - if res.is_err() { - if let Ok(level_dat_old) = crate::nbt::data::from_file(&self.config.level_dat_old_path) - { - return Ok(level_dat_old); - } - } - res.context("Failed to read level.dat") - } - - /// Generates [Spawn] data from a [de::LevelDat] - fn spawn(level_dat: &de::LevelDat) -> Spawn { - Spawn { - x: level_dat.data.spawn_x, - z: level_dat.data.spawn_z, - } - } - - /// Filter signs according to the sign pattern configuration - fn sign_filter(&self, sign: &block_entity::Sign) -> bool { - let front_text = sign.front_text.to_string(); - if self.config.sign_patterns.is_match(front_text.trim()) { - return true; - } - let back_text = sign.back_text.to_string(); - if self.config.sign_patterns.is_match(back_text.trim()) { - return true; - } - false - } - - /// Applies a single transform to a [sign::SignText] - /// - /// The regular expression is applied for each line of the sign text - /// separately (actually for each element when JSON text is used) - fn sign_text_transform(sign_text: &mut sign::SignText, transform: &(Regex, String)) { - let (regexp, replacement) = transform; - - for line in &mut sign_text.0 { - for text in &mut line.0 { - text.text = regexp.replace_all(&text.text, replacement).into_owned() - } - } - } - - /// Applies the configured transforms to the text of a sign - fn sign_transform(&self, sign: &mut block_entity::Sign) { - for transform in &self.config.sign_transforms { - Self::sign_text_transform(&mut sign.front_text, transform); - Self::sign_text_transform(&mut sign.back_text, transform); - } - } - - /// Generates [Entities] data from collected entity lists - fn entities(&self) -> Result { - let data: ProcessedEntities = storage::read_file(&self.config.entities_path_final) - .context("Failed to read entity data file")?; - - let ret = Entities { - signs: data - .block_entities - .into_iter() - .filter(|entity| match &entity.data { - BlockEntityData::Sign(sign) => self.sign_filter(sign), - }) - .map(|mut entity| { - match &mut entity.data { - BlockEntityData::Sign(sign) => self.sign_transform(sign), - }; - entity - }) - .collect(), - }; - - Ok(ret) - } - - /// Runs the viewer metadata file generation - pub fn run(self) -> Result<()> { - let level_dat = self.read_level_dat()?; - - let features = Features { - signs: !self.config.sign_patterns.is_empty(), - }; - - let mut metadata = Metadata { - mipmaps: Vec::new(), - spawn: Self::spawn(&level_dat), - features, - tile_extension: self.config.tile_extension(), - }; - - for tile_map in self.tiles.iter() { - metadata.mipmaps.push(Self::mipmap_entry(tile_map)); - } - - fs::create_with_tmpfile(&self.config.viewer_info_path, |file| { - serde_json::to_writer(file, &metadata).context("Failed to write info.json") - })?; - - let entities = self.entities()?; - fs::create_with_tmpfile(&self.config.viewer_entities_path, |file| { - serde_json::to_writer(file, &entities).context("Failed to write entities.json") - })?; - - Ok(()) - } -} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index fce2cb5..0000000 --- a/src/core/mod.rs +++ /dev/null @@ -1,214 +0,0 @@ -//! Core functions of the MinedMap CLI - -mod common; -mod entity_collector; -mod metadata_writer; -mod region_group; -mod region_processor; -mod tile_collector; -mod tile_merger; -mod tile_mipmapper; -mod tile_renderer; - -use std::{ - path::PathBuf, - sync::mpsc::{self, Receiver}, - thread, - time::Duration, -}; - -use anyhow::{Context, Result}; -use clap::Parser; -use git_version::git_version; - -use common::{Config, ImageFormat}; -use metadata_writer::MetadataWriter; -use notify::{RecommendedWatcher, RecursiveMode, Watcher as _}; -use rayon::ThreadPool; -use region_processor::RegionProcessor; -use tile_mipmapper::TileMipmapper; -use tile_renderer::TileRenderer; -use tokio::runtime::Runtime; -use tracing::{info, warn}; - -use self::entity_collector::EntityCollector; - -/// Returns the MinedMap version number -fn version() -> &'static str { - option_env!("MINEDMAP_VERSION").unwrap_or( - git_version!( - args = ["--abbrev=7", "--match=v*", "--dirty=-modified"], - cargo_prefix = "v", - ) - .strip_prefix("v") - .unwrap(), - ) -} - -/// Command line arguments for minedmap CLI -#[derive(Debug, Parser)] -#[command( - about, - version = version(), - max_term_width = 100, -)] -pub struct Args { - /// Number of parallel threads to use for processing - /// - /// If not given, only a single thread is used. Pass 0 to - /// use one thread per logical CPU core. - #[arg(short, long)] - pub jobs: Option, - /// Number of parallel threads to use for initial processing - /// - /// Passing this option only makes sense with --watch. The first run after - /// starting MinedMap will use as many parallel jobs as configured using - /// --job-initial, while subsequent regenerations of tiles will use the - /// the number configured using --jobs. - /// - /// If not given, the value from the --jobs option is used. - #[arg(long)] - pub jobs_initial: Option, - /// Enable verbose messages - #[arg(short, long)] - pub verbose: bool, - /// Watch for file changes and regenerate tiles automatically instead of - /// exiting after generation - #[arg(long)] - pub watch: bool, - /// Minimum delay between map generation cycles in watch mode - #[arg(long, value_parser = humantime::parse_duration, default_value = "30s")] - pub watch_delay: Duration, - /// Format of generated map tiles - #[arg(long, value_enum, default_value_t)] - pub image_format: ImageFormat, - /// Prefix for text of signs to show on the map - #[arg(long)] - pub sign_prefix: Vec, - /// Regular expression for text of signs to show on the map - /// - /// --sign-prefix and --sign-filter allow to filter for signs to display; - /// by default, none are visible. The options may be passed multiple times, - /// and a sign will be visible if it matches any pattern. - /// - /// To make all signs visible, pass an empty string to either option. - #[arg(long)] - pub sign_filter: Vec, - /// Regular expression replacement pattern for sign texts - /// - /// Accepts patterns of the form 's/regexp/replacement/'. Transforms - /// are applied to each line of sign texts separately. - #[arg(long)] - pub sign_transform: Vec, - /// Minecraft save directory - pub input_dir: PathBuf, - /// MinedMap data directory - pub output_dir: PathBuf, -} - -/// Configures a Rayon thread pool for parallel processing -fn setup_threads(num_threads: usize) -> Result { - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build() - .context("Failed to configure thread pool") -} - -/// Runs all MinedMap generation steps, updating all tiles as needed -fn generate(config: &Config, rt: &Runtime) -> Result<()> { - let regions = RegionProcessor::new(config).run()?; - TileRenderer::new(config, rt, ®ions).run()?; - let tiles = TileMipmapper::new(config, ®ions).run()?; - EntityCollector::new(config, ®ions).run()?; - MetadataWriter::new(config, &tiles).run() -} - -/// Creates a file watcher for the -fn create_watcher(args: &Args) -> Result<(RecommendedWatcher, Receiver<()>)> { - let (tx, rx) = mpsc::sync_channel::<()>(1); - let mut watcher = notify::recommended_watcher(move |res| { - // Ignore errors - we already have a watch trigger queued if try_send() fails - let event: notify::Event = match res { - Ok(event) => event, - Err(err) => { - warn!("Watch error: {err}"); - return; - } - }; - let notify::EventKind::Modify(modify_kind) = event.kind else { - return; - }; - if !matches!( - modify_kind, - notify::event::ModifyKind::Data(_) - | notify::event::ModifyKind::Name(notify::event::RenameMode::To) - ) { - return; - } - if !event - .paths - .iter() - .any(|path| path.ends_with("level.dat") || path.extension() == Some("mcu".as_ref())) - { - return; - } - let _ = tx.try_send(()); - })?; - watcher.watch(&args.input_dir, RecursiveMode::Recursive)?; - Ok((watcher, rx)) -} - -/// Watches the data directory for changes, returning when a change has happened -fn wait_watcher(args: &Args, watch_channel: &Receiver<()>) -> Result<()> { - info!("Watching for changes..."); - let () = watch_channel - .recv() - .context("Failed to read watch event channel")?; - info!("Change detected."); - - thread::sleep(args.watch_delay); - - let _ = watch_channel.try_recv(); - - Ok(()) -} - -/// MinedMap CLI main function -pub fn cli() -> Result<()> { - let args = Args::parse(); - let config = Config::new(&args)?; - - tracing_subscriber::fmt() - .with_max_level(if args.verbose { - tracing::Level::DEBUG - } else { - tracing::Level::INFO - }) - .with_target(false) - .init(); - - let mut pool = setup_threads(config.num_threads_initial)?; - - let rt = tokio::runtime::Builder::new_current_thread() - .build() - .unwrap(); - - let watch = args.watch.then(|| create_watcher(&args)).transpose()?; - - pool.install(|| generate(&config, &rt))?; - - let Some((_watcher, watch_channel)) = watch else { - // watch mode disabled - return Ok(()); - }; - - if config.num_threads != config.num_threads_initial { - pool = setup_threads(config.num_threads)?; - } - pool.install(move || { - loop { - wait_watcher(&args, &watch_channel)?; - generate(&config, &rt)?; - } - }) -} diff --git a/src/core/region_group.rs b/src/core/region_group.rs deleted file mode 100644 index 4357a8f..0000000 --- a/src/core/region_group.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! The generic [RegionGroup] data structure - -use std::{future::Future, iter}; - -use anyhow::Result; -use futures_util::future::OptionFuture; - -/// A generic array of 3x3 elements -/// -/// A RegionGroup is used to store information about a 3x3 neighborhood of -/// regions. -/// -/// The center element is always populated, while the 8 adjacent elements may be None. -#[derive(Debug, Clone, Copy)] -pub struct RegionGroup { - /// The element corresponding to the center of the 9x9 neighborhood - center: T, - /// The remaining elements, stored in row-first order - /// - /// The center element is always None. - neighs: [Option; 9], -} - -impl RegionGroup { - /// Constructs a new RegionGroup from a closure called for each element - /// - /// The X and Z coordinates relative to the center (in the range -1..1) - /// are passed to the closure. - /// - /// Panics of the closure returns None for the center element. - pub fn new(f: F) -> Self - where - F: Fn(i8, i8) -> Option, - { - RegionGroup { - center: f(0, 0).expect("Center element of RegionGroup must not be None"), - neighs: [ - f(-1, -1), - f(-1, 0), - f(-1, 1), - f(0, -1), - None, - f(0, 1), - f(1, -1), - f(1, 0), - f(1, 1), - ], - } - } - - /// Returns a reference to the center element - pub fn center(&self) -> &T { - &self.center - } - - /// Returns a reference to an element of the RegionGroup, if populated - /// - /// Always returns None for X and Z coordinates outside of the -1..1 range. - pub fn get(&self, x: i8, z: i8) -> Option<&T> { - if (x, z) == (0, 0) { - return Some(&self.center); - } - if !(-1..=1).contains(&x) || !(-1..=1).contains(&z) { - return None; - } - self.neighs.get((3 * x + z + 4) as usize)?.as_ref() - } - - /// Runs a closure on each element to construct a new RegionGroup - pub fn map(self, mut f: F) -> RegionGroup - where - F: FnMut(T) -> U, - { - RegionGroup { - center: f(self.center), - neighs: self.neighs.map(|entry| entry.map(&mut f)), - } - } - - /// Runs a fallible closure on each element to construct a new RegionGroup - /// - /// [Err] return values for the center element are passed up. Outer elements - /// become unpopulated when the closure fails. - pub fn try_map(self, mut f: F) -> Result> - where - F: FnMut(T) -> Result, - { - let RegionGroup { center, neighs } = self; - let center = f(center)?; - let neighs = neighs.map(|entry| entry.and_then(|value| f(value).ok())); - Ok(RegionGroup { center, neighs }) - } - - /// Runs an asynchronous closure on each element to construct a new RegionGroup - #[allow(dead_code)] - pub async fn async_map(self, mut f: F) -> RegionGroup - where - Fut: Future, - F: FnMut(T) -> Fut, - { - let center = f(self.center); - let neighs = futures_util::future::join_all( - self.neighs - .map(|entry| OptionFuture::from(entry.map(&mut f))), - ); - let (center, neighs) = futures_util::join!(center, neighs); - RegionGroup { - center, - neighs: <[Option<_>; 9]>::try_from(neighs).ok().unwrap(), - } - } - - /// Runs a fallible asynchronous closure on each element to construct a new RegionGroup - /// - /// [Err] return values for the center element are passed up. Outer elements - /// become unpopulated when the closure fails. - pub async fn async_try_map(self, mut f: F) -> Result> - where - Fut: Future>, - F: FnMut(T) -> Fut, - { - let center = f(self.center); - let neighs = futures_util::future::join_all( - self.neighs - .map(|entry| OptionFuture::from(entry.map(&mut f))), - ); - let (center, neighs) = futures_util::join!(center, neighs); - let center = center?; - - let neighs: Vec<_> = neighs - .into_iter() - .map(|entry| entry.and_then(Result::ok)) - .collect(); - let neighs = <[Option<_>; 9]>::try_from(neighs).ok().unwrap(); - - Ok(RegionGroup { center, neighs }) - } - - /// Returns an [Iterator] over all populated elements - pub fn iter(&self) -> impl Iterator { - iter::once(&self.center).chain(self.neighs.iter().filter_map(Option::as_ref)) - } -} diff --git a/src/core/region_processor.rs b/src/core/region_processor.rs deleted file mode 100644 index 74939bd..0000000 --- a/src/core/region_processor.rs +++ /dev/null @@ -1,450 +0,0 @@ -//! The [RegionProcessor] and related functions - -use std::{ffi::OsStr, path::PathBuf, sync::mpsc, time::SystemTime}; - -use anyhow::{Context, Result}; -use enum_map::{Enum, EnumMap}; -use indexmap::IndexSet; -use minedmap_resource::Biome; -use rayon::prelude::*; -use tracing::{debug, info, warn}; - -use super::common::*; -use crate::{ - io::{fs, storage}, - resource, - types::*, - world::{self, layer}, -}; - -/// Parses a filename in the format r.X.Z.mca into the contained X and Z values -fn parse_region_filename(file_name: &OsStr) -> Option { - let parts: Vec<_> = file_name.to_str()?.split('.').collect(); - let &["r", x, z, "mca"] = parts.as_slice() else { - return None; - }; - - Some(TileCoords { - x: x.parse().ok()?, - z: z.parse().ok()?, - }) -} - -/// [RegionProcessor::process_region] return values -#[derive(Debug, Clone, Copy, PartialEq, Eq, Enum)] -enum RegionProcessorStatus { - /// Region was processed - Ok, - /// Region was processed, unknown blocks or biomes were encountered - OkWithUnknown, - /// Region was unchanged and skipped - Skipped, - /// Reading the region failed, previous processed data is reused - ErrorOk, - /// Reading the region failed, no previous data available - ErrorMissing, -} - -/// Data of a region being processed by a [SingleRegionProcessor] -#[derive(Debug)] -struct SingleRegionData { - /// [IndexSet] of biomes used by the processed region - biome_list: IndexSet, - /// Processed region chunk intermediate data - chunks: ChunkArray>>, - /// Lightmap intermediate data - lightmap: image::GrayAlphaImage, - /// Processed entity intermediate data - entities: ProcessedEntities, - /// True if any unknown block or biome types were encountered during processing - has_unknown: bool, -} - -impl Default for SingleRegionData { - fn default() -> Self { - /// Width/height of the region data - const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32; - - let lightmap = image::GrayAlphaImage::new(N, N); - Self { - biome_list: Default::default(), - chunks: Default::default(), - lightmap, - entities: Default::default(), - has_unknown: false, - } - } -} - -/// Handles processing for a single region -struct SingleRegionProcessor<'a> { - /// Registry of known block types - block_types: &'a resource::BlockTypes, - /// Registry of known biome types - biome_types: &'a resource::BiomeTypes, - /// Coordinates of the region this instance is processing - coords: TileCoords, - /// Input region filename - input_path: PathBuf, - /// Processed region data output filename - output_path: PathBuf, - /// Lightmap output filename - lightmap_path: PathBuf, - /// Processed entity output filename - entities_path: PathBuf, - /// Timestamp of last modification of input file - input_timestamp: SystemTime, - /// Timestamp of last modification of processed region output file (if valid) - output_timestamp: Option, - /// Timestamp of last modification of lightmap output file (if valid) - lightmap_timestamp: Option, - /// Timestamp of last modification of entity list output file (if valid) - entities_timestamp: Option, - /// True if processed region output file needs to be updated - output_needed: bool, - /// True if lightmap output file needs to be updated - lightmap_needed: bool, - /// True if entity output file needs to be updated - entities_needed: bool, - /// Format of generated map tiles - image_format: image::ImageFormat, -} - -impl<'a> SingleRegionProcessor<'a> { - /// Initializes a [SingleRegionProcessor] - fn new(processor: &'a RegionProcessor<'a>, coords: TileCoords) -> Result { - let input_path = processor.config.region_path(coords); - let input_timestamp = fs::modified_timestamp(&input_path)?; - - let output_path = processor.config.processed_path(coords); - let output_timestamp = fs::read_timestamp(&output_path, REGION_FILE_META_VERSION); - - let lightmap_path = processor.config.tile_path(TileKind::Lightmap, 0, coords); - let lightmap_timestamp = fs::read_timestamp(&lightmap_path, LIGHTMAP_FILE_META_VERSION); - - let entities_path = processor.config.entities_path(0, coords); - let entities_timestamp = fs::read_timestamp(&entities_path, ENTITIES_FILE_META_VERSION); - - let output_needed = Some(input_timestamp) > output_timestamp; - let lightmap_needed = Some(input_timestamp) > lightmap_timestamp; - let entities_needed = Some(input_timestamp) > entities_timestamp; - - Ok(SingleRegionProcessor { - block_types: &processor.block_types, - biome_types: &processor.biome_types, - coords, - input_path, - output_path, - lightmap_path, - entities_path, - input_timestamp, - output_timestamp, - lightmap_timestamp, - entities_timestamp, - output_needed, - lightmap_needed, - entities_needed, - image_format: processor.config.tile_image_format(), - }) - } - - /// Renders a lightmap subtile from chunk block light data - fn render_chunk_lightmap( - block_light: Box, - ) -> image::GrayAlphaImage { - /// Width/height of generated chunk lightmap - const N: u32 = BLOCKS_PER_CHUNK as u32; - - image::GrayAlphaImage::from_fn(N, N, |x, z| { - let v: f32 = block_light[LayerBlockCoords { - x: BlockX::new(x), - z: BlockZ::new(z), - }] - .into(); - image::LumaA([0, (192.0 * (1.0 - v / 15.0)) as u8]) - }) - } - - /// Saves processed region data - /// - /// The timestamp is the time of the last modification of the input region data. - fn save_region(&self, processed_region: &ProcessedRegion) -> Result<()> { - if !self.output_needed { - return Ok(()); - } - - storage::write_file( - &self.output_path, - processed_region, - REGION_FILE_META_VERSION, - self.input_timestamp, - ) - } - - /// Saves a lightmap tile - /// - /// The timestamp is the time of the last modification of the input region data. - fn save_lightmap(&self, lightmap: &image::GrayAlphaImage) -> Result<()> { - if !self.lightmap_needed { - return Ok(()); - } - - fs::create_with_timestamp( - &self.lightmap_path, - LIGHTMAP_FILE_META_VERSION, - self.input_timestamp, - |file| { - lightmap - .write_to(file, self.image_format) - .context("Failed to save image") - }, - ) - } - - /// Saves processed entity data - /// - /// The timestamp is the time of the last modification of the input region data. - fn save_entities(&self, entities: &mut ProcessedEntities) -> Result<()> { - if !self.entities_needed { - return Ok(()); - } - - entities.block_entities.sort_unstable(); - - storage::write_file( - &self.entities_path, - entities, - ENTITIES_FILE_META_VERSION, - self.input_timestamp, - ) - } - - /// Processes a single chunk - fn process_chunk( - &self, - data: &mut SingleRegionData, - chunk_coords: ChunkCoords, - chunk_data: world::de::Chunk, - ) -> Result<()> { - let (chunk, has_unknown) = - world::chunk::Chunk::new(&chunk_data, self.block_types, self.biome_types) - .with_context(|| format!("Failed to decode chunk {chunk_coords:?}"))?; - data.has_unknown |= has_unknown; - - if self.output_needed || self.lightmap_needed { - if let Some(layer::LayerData { - blocks, - biomes, - block_light, - depths, - }) = world::layer::top_layer(&mut data.biome_list, &chunk) - .with_context(|| format!("Failed to process chunk {chunk_coords:?}"))? - { - if self.output_needed { - data.chunks[chunk_coords] = Some(Box::new(ProcessedChunk { - blocks, - biomes, - depths, - })); - } - - if self.lightmap_needed { - let chunk_lightmap = Self::render_chunk_lightmap(block_light); - overlay_chunk(&mut data.lightmap, &chunk_lightmap, chunk_coords); - } - } - } - - if self.entities_needed { - let mut block_entities = chunk.block_entities().with_context(|| { - format!("Failed to process block entities for chunk {chunk_coords:?}") - })?; - data.entities.block_entities.append(&mut block_entities); - } - - Ok(()) - } - - /// Processes the chunks of the region - fn process_chunks(&self, data: &mut SingleRegionData) -> Result<()> { - crate::nbt::region::from_file(&self.input_path)?.foreach_chunk( - |chunk_coords, chunk_data| self.process_chunk(data, chunk_coords, chunk_data), - ) - } - - /// Processes the region - fn run(&self) -> Result { - if !self.output_needed && !self.lightmap_needed && !self.entities_needed { - debug!( - "Skipping unchanged region r.{}.{}.mca", - self.coords.x, self.coords.z - ); - return Ok(RegionProcessorStatus::Skipped); - } - - debug!( - "Processing region r.{}.{}.mca", - self.coords.x, self.coords.z - ); - - let mut data = SingleRegionData::default(); - - if let Err(err) = self.process_chunks(&mut data) { - if self.output_timestamp.is_some() - && self.lightmap_timestamp.is_some() - && self.entities_timestamp.is_some() - { - warn!( - "Failed to process region {:?}, using old data: {:?}", - self.coords, err - ); - return Ok(RegionProcessorStatus::ErrorOk); - } else { - warn!( - "Failed to process region {:?}, no old data available: {:?}", - self.coords, err - ); - return Ok(RegionProcessorStatus::ErrorMissing); - } - } - - let processed_region = ProcessedRegion { - biome_list: data.biome_list.into_iter().collect(), - chunks: data.chunks, - }; - - self.save_region(&processed_region)?; - self.save_lightmap(&data.lightmap)?; - self.save_entities(&mut data.entities)?; - - Ok(if data.has_unknown { - RegionProcessorStatus::OkWithUnknown - } else { - RegionProcessorStatus::Ok - }) - } -} - -/// Type with methods for processing the regions of a Minecraft save directory -/// -/// The RegionProcessor builds lightmap tiles as well as processed region data -/// consumed by subsequent generation steps. -pub struct RegionProcessor<'a> { - /// Registry of known block types - block_types: resource::BlockTypes, - /// Registry of known biome types - biome_types: resource::BiomeTypes, - /// Common MinedMap configuration from command line - config: &'a Config, -} - -impl<'a> RegionProcessor<'a> { - /// Constructs a new RegionProcessor - pub fn new(config: &'a Config) -> Self { - RegionProcessor { - block_types: resource::BlockTypes::default(), - biome_types: resource::BiomeTypes::default(), - config, - } - } - - /// Generates a list of all regions of the input Minecraft save data - fn collect_regions(&self) -> Result> { - Ok(self - .config - .region_dir - .read_dir() - .with_context(|| { - format!( - "Failed to read directory {}", - self.config.region_dir.display() - ) - })? - .filter_map(|entry| entry.ok()) - .filter(|entry| { - (|| { - // We are only interested in regular files - let file_type = entry.file_type().ok()?; - if !file_type.is_file() { - return None; - } - - let metadata = entry.metadata().ok()?; - if metadata.len() == 0 { - return None; - } - Some(()) - })() - .is_some() - }) - .filter_map(|entry| parse_region_filename(&entry.file_name())) - .collect()) - } - - /// Processes a single region file - fn process_region(&self, coords: TileCoords) -> Result { - SingleRegionProcessor::new(self, coords)?.run() - } - - /// Iterates over all region files of a Minecraft save directory - /// - /// Returns a list of the coordinates of all processed regions - pub fn run(self) -> Result> { - use RegionProcessorStatus as Status; - - fs::create_dir_all(&self.config.processed_dir)?; - fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, 0))?; - fs::create_dir_all(&self.config.entities_dir(0))?; - - info!("Processing region files..."); - - let (region_send, region_recv) = mpsc::channel(); - let (status_send, status_recv) = mpsc::channel(); - - self.collect_regions()?.par_iter().try_for_each(|&coords| { - let ret = self - .process_region(coords) - .with_context(|| format!("Failed to process region {coords:?}"))?; - - if ret != Status::ErrorMissing { - region_send.send(coords).unwrap(); - } - - status_send.send(ret).unwrap(); - - anyhow::Ok(()) - })?; - - drop(region_send); - let mut regions: Vec<_> = region_recv.into_iter().collect(); - - drop(status_send); - - let mut status = EnumMap::<_, usize>::default(); - for ret in status_recv { - status[ret] += 1; - } - - info!( - "Processed region files ({} processed, {} unchanged, {} errors)", - status[Status::Ok] + status[Status::OkWithUnknown], - status[Status::Skipped], - status[Status::ErrorOk] + status[Status::ErrorMissing], - ); - - if status[Status::OkWithUnknown] > 0 { - warn!("Unknown block or biome types found during processing"); - eprint!(concat!( - "\n", - " If you're encountering this issue with an unmodified Minecraft version supported by MinedMap,\n", - " please file a bug report including the output with the --verbose flag.\n", - "\n", - )); - } - - // Sort regions in a zig-zag pattern to optimize cache usage - regions.sort_unstable_by_key(|&TileCoords { x, z }| (x, if x % 2 == 0 { z } else { -z })); - - Ok(regions) - } -} diff --git a/src/core/tile_collector.rs b/src/core/tile_collector.rs deleted file mode 100644 index dfc6085..0000000 --- a/src/core/tile_collector.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! A trait for recursively processing tiles -//! -//! Used for mipmap generation and collecting entity data - -use std::sync::mpsc; - -use anyhow::Result; -use rayon::prelude::*; - -use super::common::*; - -/// Helper to determine if no further mipmap levels are needed -/// -/// If all tile coordinates are -1 or 0, further mipmap levels will not -/// decrease the number of tiles and mipmap generated is considered finished. -fn done(tiles: &TileCoordMap) -> bool { - tiles - .0 - .iter() - .all(|(z, xs)| (-1..=0).contains(z) && xs.iter().all(|x| (-1..=0).contains(x))) -} - -/// Derives the map of populated tile coordinates for the next mipmap level -fn map_coords(tiles: &TileCoordMap) -> TileCoordMap { - let mut ret = TileCoordMap::default(); - - for (&z, xs) in &tiles.0 { - for &x in xs { - let xt = x >> 1; - let zt = z >> 1; - - ret.0.entry(zt).or_default().insert(xt); - } - } - - ret -} - -/// Trait to implement for collecting tiles recursively -pub trait TileCollector: Sync { - /// Return value of [TileCollector::collect_one] - type CollectOutput: Send; - - /// List of level 0 tiles - fn tiles(&self) -> &[TileCoords]; - - /// Called at the beginning of each level of processing - fn prepare(&self, level: usize) -> Result<()>; - - /// Called at the end of each level of processing - fn finish( - &self, - level: usize, - outputs: impl Iterator, - ) -> Result<()>; - - /// Called for each tile coordinate of the level that is currently being generated - fn collect_one( - &self, - level: usize, - coords: TileCoords, - prev: &TileCoordMap, - ) -> Result; - - /// Collects tiles recursively - fn collect_tiles(&self) -> Result> { - let mut tile_stack = { - let mut tile_map = TileCoordMap::default(); - - for &TileCoords { x, z } in self.tiles() { - tile_map.0.entry(z).or_default().insert(x); - } - - vec![tile_map] - }; - - loop { - let level = tile_stack.len(); - let prev = &tile_stack[level - 1]; - if done(prev) { - break; - } - - self.prepare(level)?; - - let next = map_coords(prev); - - let (send, recv) = mpsc::channel(); - - next.0 - .par_iter() - .flat_map(|(&z, xs)| xs.par_iter().map(move |&x| TileCoords { x, z })) - .try_for_each(|coords| { - let output = self.collect_one(level, coords, prev)?; - send.send(output).unwrap(); - anyhow::Ok(()) - })?; - - drop(send); - self.finish(level, recv.into_iter())?; - - tile_stack.push(next); - } - - Ok(tile_stack) - } -} diff --git a/src/core/tile_merger.rs b/src/core/tile_merger.rs deleted file mode 100644 index 6f3cc22..0000000 --- a/src/core/tile_merger.rs +++ /dev/null @@ -1,97 +0,0 @@ -//! Mipmap-style merging of tiles - -use std::{ - fs::File, - io::BufWriter, - path::{Path, PathBuf}, - time::SystemTime, -}; - -use anyhow::Result; -use tracing::warn; - -use super::common::*; -use crate::io::fs; - -/// [TileMerger::merge_tiles] return -#[derive(Debug, Clone, Copy)] -pub enum Stat { - /// None of the input files were found - NotFound, - /// The output file is up-to-date - Skipped, - /// The output file is regenerated - Regenerate, -} - -/// A source file for the [TileMerger] -/// -/// The tuple elements are X and Z coordinate offsets in the range [0, 1], -/// the file path and the time of last change of the input. -pub type Source = ((i32, i32), PathBuf, SystemTime); - -/// Reusable trait for mipmap-style tile merging with change tracking -pub trait TileMerger { - /// [fs::FileMetaVersion] of input and output files - /// - /// The version in the file metadata on disk must match the returned - /// version for the a to be considered up-to-date. - fn file_meta_version(&self) -> fs::FileMetaVersion; - - /// Returns the paths of input and output files - fn tile_path(&self, level: usize, coords: TileCoords) -> PathBuf; - - /// Can be used to log the processing status - fn log(&self, _output_path: &Path, _stat: Stat) {} - - /// Handles the actual merging of source files - fn write_tile(&self, file: &mut BufWriter, sources: &[Source]) -> Result<()>; - - /// Generates a tile at given coordinates and mipmap level - fn merge_tiles(&self, level: usize, coords: TileCoords, prev: &TileCoordMap) -> Result { - let version = self.file_meta_version(); - let output_path = self.tile_path(level, coords); - let output_timestamp = fs::read_timestamp(&output_path, version); - - let sources: Vec<_> = [(0, 0), (0, 1), (1, 0), (1, 1)] - .into_iter() - .filter_map(|(dx, dz)| { - let source_coords = TileCoords { - x: 2 * coords.x + dx, - z: 2 * coords.z + dz, - }; - if !prev.contains(source_coords) { - return None; - } - - let source_path = self.tile_path(level - 1, source_coords); - let timestamp = match fs::modified_timestamp(&source_path) { - Ok(timestamp) => timestamp, - Err(err) => { - warn!("{:?}", err); - return None; - } - }; - Some(((dx, dz), source_path, timestamp)) - }) - .collect(); - - let Some(input_timestamp) = sources.iter().map(|(_, _, ts)| *ts).max() else { - self.log(&output_path, Stat::NotFound); - return Ok(Stat::NotFound); - }; - - if Some(input_timestamp) <= output_timestamp { - self.log(&output_path, Stat::Skipped); - return Ok(Stat::Skipped); - } - - self.log(&output_path, Stat::Regenerate); - - fs::create_with_timestamp(&output_path, version, input_timestamp, |file| { - self.write_tile(file, &sources) - })?; - - Ok(Stat::Regenerate) - } -} diff --git a/src/core/tile_mipmapper.rs b/src/core/tile_mipmapper.rs deleted file mode 100644 index 2eda0e9..0000000 --- a/src/core/tile_mipmapper.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! The [TileMipmapper] - -use std::{marker::PhantomData, ops::Add}; - -use anyhow::{Context, Result}; -use tracing::{debug, info, warn}; - -use super::{ - common::*, - tile_collector::TileCollector, - tile_merger::{self, TileMerger}, -}; -use crate::{io::fs, types::*}; - -/// Counters for the number of processed and total tiles -/// -/// Used as return of [TileMipmapper::collect_one] -#[derive(Debug, Clone, Copy)] -pub struct MipmapStat { - /// Total number of tiles - total: usize, - /// Processed number of tiles - processed: usize, -} - -impl From for MipmapStat { - fn from(value: tile_merger::Stat) -> Self { - match value { - tile_merger::Stat::NotFound => MipmapStat { - total: 0, - processed: 0, - }, - tile_merger::Stat::Skipped => MipmapStat { - total: 1, - processed: 0, - }, - tile_merger::Stat::Regenerate => MipmapStat { - total: 1, - processed: 1, - }, - } - } -} - -impl Add for MipmapStat { - type Output = MipmapStat; - - fn add(self, rhs: Self) -> Self::Output { - MipmapStat { - total: self.total + rhs.total, - processed: self.processed + rhs.processed, - } - } -} - -/// [TileMerger] for map tile images -struct MapMerger<'a, P> { - /// Common MinedMap configuration from command line - config: &'a Config, - /// Tile kind (map or lightmap) - kind: TileKind, - /// Pixel format type - _pixel: PhantomData

, -} - -impl<'a, P> MapMerger<'a, P> { - /// Creates a new [MapMerger] - fn new(config: &'a Config, kind: TileKind) -> Self { - MapMerger { - config, - kind, - _pixel: PhantomData, - } - } -} - -impl TileMerger for MapMerger<'_, P> -where - [P::Subpixel]: image::EncodableLayout, - image::ImageBuffer>: Into, -{ - fn file_meta_version(&self) -> fs::FileMetaVersion { - MIPMAP_FILE_META_VERSION - } - - fn tile_path(&self, level: usize, coords: TileCoords) -> std::path::PathBuf { - self.config.tile_path(self.kind, level, coords) - } - - fn log(&self, output_path: &std::path::Path, stat: super::tile_merger::Stat) { - match stat { - super::tile_merger::Stat::NotFound => {} - super::tile_merger::Stat::Skipped => { - debug!( - "Skipping unchanged mipmap tile {}", - output_path - .strip_prefix(&self.config.output_dir) - .expect("tile path must be in output directory") - .display(), - ); - } - super::tile_merger::Stat::Regenerate => { - debug!( - "Rendering mipmap tile {}", - output_path - .strip_prefix(&self.config.output_dir) - .expect("tile path must be in output directory") - .display(), - ); - } - }; - } - - fn write_tile( - &self, - file: &mut std::io::BufWriter, - sources: &[super::tile_merger::Source], - ) -> Result<()> { - /// Tile width/height - const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32; - - let mut image: image::DynamicImage = - image::ImageBuffer::>::new(N, N).into(); - - for ((dx, dz), source_path, _) in sources { - let source = match image::open(source_path) { - Ok(source) => source, - Err(err) => { - warn!( - "Failed to read source image {}: {:?}", - source_path.display(), - err, - ); - continue; - } - }; - let resized = source.resize(N / 2, N / 2, image::imageops::FilterType::Triangle); - image::imageops::overlay( - &mut image, - &resized, - *dx as i64 * (N / 2) as i64, - *dz as i64 * (N / 2) as i64, - ); - } - - image - .write_to(file, self.config.tile_image_format()) - .context("Failed to save image") - } -} - -/// Generates mipmap tiles from full-resolution tile images -pub struct TileMipmapper<'a> { - /// Common MinedMap configuration from command line - config: &'a Config, - /// List of populated tiles for base mipmap level (level 0) - regions: &'a [TileCoords], -} - -impl TileCollector for TileMipmapper<'_> { - type CollectOutput = MipmapStat; - - fn tiles(&self) -> &[TileCoords] { - self.regions - } - - fn prepare(&self, level: usize) -> Result<()> { - info!("Generating level {} mipmaps...", level); - - fs::create_dir_all(&self.config.tile_dir(TileKind::Map, level))?; - fs::create_dir_all(&self.config.tile_dir(TileKind::Lightmap, level))?; - - Ok(()) - } - - fn finish( - &self, - level: usize, - outputs: impl Iterator, - ) -> Result<()> { - let stat = outputs.fold( - MipmapStat { - total: 0, - processed: 0, - }, - MipmapStat::add, - ); - info!( - "Generated level {} mipmaps ({} processed, {} unchanged)", - level, - stat.processed, - stat.total - stat.processed, - ); - - Ok(()) - } - - fn collect_one( - &self, - level: usize, - coords: TileCoords, - prev: &TileCoordMap, - ) -> Result { - let map_stat = self.render_mipmap::>(TileKind::Map, level, coords, prev)?; - let lightmap_stat = - self.render_mipmap::>(TileKind::Lightmap, level, coords, prev)?; - Ok(map_stat + lightmap_stat) - } -} - -impl<'a> TileMipmapper<'a> { - /// Constructs a new TileMipmapper - pub fn new(config: &'a Config, regions: &'a [TileCoords]) -> Self { - TileMipmapper { config, regions } - } - - /// Renders and saves a single mipmap tile image - /// - /// Each mipmap tile is rendered by taking 2x2 tiles from the - /// previous level and scaling them down by 50%. - fn render_mipmap( - &self, - kind: TileKind, - level: usize, - coords: TileCoords, - prev: &TileCoordMap, - ) -> Result - where - [P::Subpixel]: image::EncodableLayout, - image::ImageBuffer>: Into, - { - let merger = MapMerger::

::new(self.config, kind); - let ret = merger.merge_tiles(level, coords, prev)?; - Ok(ret.into()) - } - - /// Runs the mipmap generation - pub fn run(self) -> Result> { - self.collect_tiles() - } -} diff --git a/src/core/tile_renderer.rs b/src/core/tile_renderer.rs deleted file mode 100644 index 0b534b8..0000000 --- a/src/core/tile_renderer.rs +++ /dev/null @@ -1,341 +0,0 @@ -//! The [TileRenderer] and related types and functions - -use std::{ - num::NonZeroUsize, - path::PathBuf, - sync::{Arc, Mutex}, - time::SystemTime, -}; - -use anyhow::{Context, Result}; -use lru::LruCache; -use rayon::prelude::*; -use tokio::sync::OnceCell; -use tracing::{debug, info}; - -use super::{common::*, region_group::RegionGroup}; -use crate::{ - io::{fs, storage}, - resource::{Colorf, block_color, needs_biome}, - types::*, - util::coord_offset, -}; - -/// Type for referencing loaded [ProcessedRegion] data -type RegionRef = Arc; - -/// Returns the index of the biome at a block coordinate -/// -/// The passed chunk and block coordinates relative to the center of the -/// region group is offset by *dx* and *dz*. -/// -/// The returned tuple contains the relative region coordinates the offset coordinate -/// ends up in (in the range -1..1) and the index in that region's biome list. -fn biome_at( - region_group: &RegionGroup, - chunk: ChunkCoords, - block: LayerBlockCoords, - dx: i32, - dz: i32, -) -> Option<(i8, i8, u16)> { - let (region_x, chunk_x, block_x) = coord_offset(chunk.x, block.x, dx); - let (region_z, chunk_z, block_z) = coord_offset(chunk.z, block.z, dz); - let chunk = ChunkCoords { - x: chunk_x, - z: chunk_z, - }; - let block = LayerBlockCoords { - x: block_x, - z: block_z, - }; - let region = region_group.get(region_x, region_z)?; - Some(( - region_x, - region_z, - region.chunks[chunk].as_ref()?.biomes[block]?.get() - 1, - )) -} - -/// The TileRenderer generates map tiles from processed region data -pub struct TileRenderer<'a> { - /// Common MinedMap configuration from command line - config: &'a Config, - /// Runtime for asynchronous region loading - rt: &'a tokio::runtime::Runtime, - /// List of populated regions to render tiles for - regions: &'a [TileCoords], - /// Set of populated regions for fast existence checking - region_set: rustc_hash::FxHashSet, - /// Cache of previously loaded regions - region_cache: Mutex>>>, -} - -impl<'a> TileRenderer<'a> { - /// Constructs a new TileRenderer - pub fn new( - config: &'a Config, - rt: &'a tokio::runtime::Runtime, - regions: &'a [TileCoords], - ) -> Self { - let region_cache = Mutex::new(LruCache::new( - NonZeroUsize::new(6 + 6 * config.num_threads).unwrap(), - )); - let region_set = regions.iter().copied().collect(); - TileRenderer { - config, - rt, - regions, - region_set, - region_cache, - } - } - - /// Loads [ProcessedRegion] for a region or returns previously loaded data from the region cache - async fn load_region(&self, processed_path: PathBuf) -> Result { - let region_loader = { - let mut region_cache = self.region_cache.lock().unwrap(); - if let Some(region_loader) = region_cache.get(&processed_path) { - Arc::clone(region_loader) - } else { - let region_loader = Default::default(); - region_cache.put(processed_path.clone(), Arc::clone(®ion_loader)); - region_loader - } - }; - - region_loader - .get_or_try_init(|| async { - storage::read_file(&processed_path).context("Failed to load processed region data") - }) - .await - .cloned() - } - - /// Loads a 3x3 neighborhood of processed region data - async fn load_region_group( - &self, - processed_paths: RegionGroup, - ) -> Result> { - processed_paths - .async_try_map(move |path| self.load_region(path)) - .await - } - - /// Computes the color of a tile pixel - fn block_color_at( - region_group: &RegionGroup, - chunk: &ProcessedChunk, - chunk_coords: ChunkCoords, - block_coords: LayerBlockCoords, - ) -> Option { - /// Helper for keys in the weight table - /// - /// Hashing the value as a single u32 is more efficient than hashing - /// the tuple elements separately. - fn biome_key((dx, dz, index): (i8, i8, u16)) -> u32 { - (dx as u8 as u32) | ((dz as u8 as u32) << 8) | ((index as u32) << 16) - } - - /// One quadrant of the kernel used to smooth biome edges - /// - /// The kernel is mirrored in X und Z direction to build the full 5x5 - /// smoothing kernel. - const SMOOTH: [[f32; 3]; 3] = [[41.0, 26.0, 7.0], [26.0, 16.0, 4.0], [7.0, 4.0, 1.0]]; - /// Maximum X coordinate offset to take into account for biome smoothing - const X: isize = SMOOTH[0].len() as isize - 1; - /// Maximum Z coordinate offset to take into account for biome smoothing - const Z: isize = SMOOTH.len() as isize - 1; - - let block = chunk.blocks[block_coords]?; - let depth = chunk.depths[block_coords]?; - - if !needs_biome(block) { - return Some(block_color(block, None, depth.0 as f32)); - } - - let mut weights = rustc_hash::FxHashMap::::default(); - for dz in -Z..=Z { - for dx in -X..=X { - let w = SMOOTH[dz.unsigned_abs()][dx.unsigned_abs()]; - if w == 0.0 { - continue; - } - - let Some(biome) = biome_at( - region_group, - chunk_coords, - block_coords, - dx as i32, - dz as i32, - ) else { - continue; - }; - - let value = weights.entry(biome_key(biome)).or_default(); - value.0 = biome; - value.1 += w; - } - } - - if weights.is_empty() { - return None; - } - - let mut color = Colorf::ZERO; - let mut total = 0.0; - - for ((region_x, region_z, index), w) in weights.into_values() { - let region = region_group.get(region_x, region_z)?; - let biome = region.biome_list.get(usize::from(index))?; - - total += w; - color += w * block_color(block, Some(biome), depth.0 as f32); - } - - Some(color / total) - } - - /// Renders a chunk subtile into a region tile image - fn render_chunk( - image: &mut image::RgbaImage, - region_group: &RegionGroup, - chunk: &ProcessedChunk, - chunk_coords: ChunkCoords, - ) { - /// Width/height of a chunk subtile - const N: u32 = BLOCKS_PER_CHUNK as u32; - - let chunk_image = image::RgbaImage::from_fn(N, N, |x, z| { - let block_coords = LayerBlockCoords { - x: BlockX::new(x), - z: BlockZ::new(z), - }; - let color = Self::block_color_at(region_group, chunk, chunk_coords, block_coords); - image::Rgba( - color - .map(|c| [c[0] as u8, c[1] as u8, c[2] as u8, 255]) - .unwrap_or_default(), - ) - }); - overlay_chunk(image, &chunk_image, chunk_coords); - } - - /// Renders a region tile image - fn render_region(image: &mut image::RgbaImage, region_group: &RegionGroup) { - for (coords, chunk) in region_group.center().chunks.iter() { - let Some(chunk) = chunk else { - continue; - }; - - Self::render_chunk(image, region_group, chunk, coords); - } - } - - /// Returns the filename of the processed data for a region and the time of its last modification - fn processed_source(&self, coords: TileCoords) -> Result<(PathBuf, SystemTime)> { - let path = self.config.processed_path(coords); - let timestamp = fs::modified_timestamp(&path)?; - Ok((path, timestamp)) - } - - /// Returns the filenames of the processed data for a 3x3 neighborhood of a region - /// and the time of last modification for any of them - fn processed_sources(&self, coords: TileCoords) -> Result<(RegionGroup, SystemTime)> { - let sources = RegionGroup::new(|x, z| { - Some(TileCoords { - x: coords.x + (x as i32), - z: coords.z + (z as i32), - }) - .filter(|entry| self.region_set.contains(entry)) - }) - .try_map(|entry| self.processed_source(entry)) - .with_context(|| format!("Region {coords:?} from previous step must exist"))?; - - let max_timestamp = *sources - .iter() - .map(|(_, timestamp)| timestamp) - .max() - .expect("at least one timestamp must exist"); - - let paths = sources.map(|(path, _)| path); - Ok((paths, max_timestamp)) - } - - /// Renders and saves a region tile image - fn render_tile(&self, coords: TileCoords) -> Result { - /// Width/height of a tile image - const N: u32 = (BLOCKS_PER_CHUNK * CHUNKS_PER_REGION) as u32; - - let (processed_paths, processed_timestamp) = self.processed_sources(coords)?; - - let output_path = self.config.tile_path(TileKind::Map, 0, coords); - let output_timestamp = fs::read_timestamp(&output_path, MAP_FILE_META_VERSION); - - if Some(processed_timestamp) <= output_timestamp { - debug!( - "Skipping unchanged tile {}", - output_path - .strip_prefix(&self.config.output_dir) - .expect("tile path must be in output directory") - .display(), - ); - return Ok(false); - } - - debug!( - "Rendering tile {}", - output_path - .strip_prefix(&self.config.output_dir) - .expect("tile path must be in output directory") - .display(), - ); - - let region_group = self - .rt - .block_on(self.load_region_group(processed_paths)) - .with_context(|| format!("Region {coords:?} from previous step must be loadable"))?; - let mut image = image::RgbaImage::new(N, N); - Self::render_region(&mut image, ®ion_group); - - fs::create_with_timestamp( - &output_path, - MAP_FILE_META_VERSION, - processed_timestamp, - |file| { - image - .write_to(file, self.config.tile_image_format()) - .context("Failed to save image") - }, - )?; - - Ok(true) - } - - /// Runs the tile generation - pub fn run(self) -> Result<()> { - fs::create_dir_all(&self.config.tile_dir(TileKind::Map, 0))?; - - info!("Rendering map tiles..."); - - // Use par_bridge to process items in order (for better use of region cache) - let processed = self - .regions - .iter() - .par_bridge() - .map(|&coords| { - anyhow::Ok(usize::from( - self.render_tile(coords) - .with_context(|| format!("Failed to render tile {coords:?}"))?, - )) - }) - .try_reduce(|| 0, |a, b| Ok(a + b))?; - - info!( - "Rendered map tiles ({} processed, {} unchanged)", - processed, - self.regions.len() - processed, - ); - - Ok(()) - } -} diff --git a/src/io/fs.rs b/src/io/fs.rs deleted file mode 100644 index 7960b25..0000000 --- a/src/io/fs.rs +++ /dev/null @@ -1,186 +0,0 @@ -//! Helpers and common functions for filesystem access - -use std::{ - fs::{self, File}, - io::{BufReader, BufWriter, Read, Write}, - path::{Path, PathBuf}, - time::SystemTime, -}; - -use anyhow::{Context, Ok, Result}; -use serde::{Deserialize, Serialize}; - -/// A file metadata version number -/// -/// Deserialized metadata with non-current version number are considered invalid -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] -pub struct FileMetaVersion(pub u32); - -/// Metadata stored with generated files to track required incremental updates -#[derive(Debug, Serialize, Deserialize)] -struct FileMeta { - /// Version of data described by the FileMeta - version: FileMetaVersion, - /// Timestamp stored with generated data - /// - /// This timestamp is always the time of last modification of the inputs - /// that were used to generate the file described by the FileMeta. - timestamp: SystemTime, -} - -/// Helper for creating suffixed file paths -fn suffix_name(path: &Path, suffix: &str) -> PathBuf { - let mut file_name = path.file_name().unwrap_or_default().to_os_string(); - file_name.push(suffix); - - let mut ret = path.to_path_buf(); - ret.set_file_name(file_name); - ret -} - -/// Derives the filename for temporary storage of data during generation -fn tmpfile_name(path: &Path) -> PathBuf { - suffix_name(path, ".tmp") -} - -/// Derives the filename for associated metadata for generated files -fn metafile_name(path: &Path) -> PathBuf { - suffix_name(path, ".meta") -} - -/// Creates a directory including all its parents -/// -/// Wrapper around [fs::create_dir_all] that adds a more descriptive error message -pub fn create_dir_all(path: &Path) -> Result<()> { - fs::create_dir_all(path) - .with_context(|| format!("Failed to create directory {}", path.display(),)) -} - -/// Renames a file or directory -/// -/// Wrapper around [fs::rename] that adds a more descriptive error message -pub fn rename(from: &Path, to: &Path) -> Result<()> { - fs::rename(from, to) - .with_context(|| format!("Failed to rename {} to {}", from.display(), to.display())) -} - -/// Creates a new file -/// -/// The contents of the file are defined by the passed function. -pub fn create(path: &Path, f: F) -> Result -where - F: FnOnce(&mut BufWriter) -> Result, -{ - (|| { - let file = File::create(path)?; - let mut writer = BufWriter::new(file); - - let ret = f(&mut writer)?; - writer.flush()?; - - Ok(ret) - })() - .with_context(|| format!("Failed to write file {}", path.display())) -} - -/// Checks whether the contents of two files are equal -pub fn equal(path1: &Path, path2: &Path) -> Result { - let mut file1 = BufReader::new( - fs::File::open(path1) - .with_context(|| format!("Failed to open file {}", path1.display()))?, - ) - .bytes(); - let mut file2 = BufReader::new( - fs::File::open(path2) - .with_context(|| format!("Failed to open file {}", path2.display()))?, - ) - .bytes(); - - Ok(loop { - match (file1.next().transpose()?, file2.next().transpose()?) { - (Some(b1), Some(b2)) if b1 == b2 => continue, - (None, None) => break true, - _ => break false, - }; - }) -} - -/// Creates a new file, temporarily storing its contents in a temporary file -/// -/// Storing the data in a temporary file prevents leaving half-written files -/// when the function is interrupted. In addition, the old and new contents of -/// the file are compared if a file with the same name already exists, and the -/// file timestamp is only updated if the contents have changed. -pub fn create_with_tmpfile(path: &Path, f: F) -> Result -where - F: FnOnce(&mut BufWriter) -> Result, -{ - let tmp_path = tmpfile_name(path); - let mut cleanup = true; - - let ret = (|| { - let ret = create(&tmp_path, f)?; - if !matches!(equal(path, &tmp_path), Result::Ok(true)) { - rename(&tmp_path, path)?; - cleanup = false; - } - Ok(ret) - })(); - - if cleanup { - let _ = fs::remove_file(&tmp_path); - } - - ret -} - -/// Returns the time of last modification for a given file path -pub fn modified_timestamp(path: &Path) -> Result { - fs::metadata(path) - .and_then(|meta| meta.modified()) - .with_context(|| { - format!( - "Failed to get modified timestamp of file {}", - path.display() - ) - }) -} - -/// Reads the stored timestamp from file metadata for a file previously written -/// using [create_with_timestamp] -pub fn read_timestamp(path: &Path, version: FileMetaVersion) -> Option { - let meta_path = metafile_name(path); - let mut file = BufReader::new(fs::File::open(meta_path).ok()?); - - let meta: FileMeta = serde_json::from_reader(&mut file).ok()?; - if meta.version != version { - return None; - } - - Some(meta.timestamp) -} - -/// Creates a new file, temporarily storing its contents in a temporary file -/// like [create_with_tmpfile], and storing a timestamp in a metadata file -/// if successful -/// -/// The timestamp can be retrieved later using [read_timestamp]. -pub fn create_with_timestamp( - path: &Path, - version: FileMetaVersion, - timestamp: SystemTime, - f: F, -) -> Result -where - F: FnOnce(&mut BufWriter) -> Result, -{ - let ret = create_with_tmpfile(path, f)?; - - let meta_path = metafile_name(path); - create(&meta_path, |file| { - serde_json::to_writer(file, &FileMeta { version, timestamp })?; - Ok(()) - })?; - - Ok(ret) -} diff --git a/src/io/mod.rs b/src/io/mod.rs deleted file mode 100644 index bfe2a2c..0000000 --- a/src/io/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Input/output functions - -pub mod fs; -pub mod storage; diff --git a/src/io/storage.rs b/src/io/storage.rs deleted file mode 100644 index ae311de..0000000 --- a/src/io/storage.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! Functions for serializing and deserializing MinedMap data structures efficiently -//! -//! Data is serialized using Bincode and compressed using zstd. - -use std::{ - fs::File, - io::{Read, Write}, - path::Path, - time::SystemTime, -}; - -use anyhow::{Context, Result}; -use bincode::{Decode, Encode}; - -use super::fs; - -/// Bincode configuration -const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard(); - -/// Serializes data and writes it to a writer -pub fn write(writer: &mut W, value: &T) -> Result<()> { - let data = bincode::encode_to_vec(value, BINCODE_CONFIG)?; - let len = u32::try_from(data.len())?; - let compressed = zstd::bulk::compress(&data, 1)?; - drop(data); - - writer.write_all(&len.to_be_bytes())?; - writer.write_all(&compressed)?; - - Ok(()) -} - -/// Serializes data and stores it in a file -/// -/// A timestamp is stored in an assiciated metadata file. -pub fn write_file( - path: &Path, - value: &T, - version: fs::FileMetaVersion, - timestamp: SystemTime, -) -> Result<()> { - fs::create_with_timestamp(path, version, timestamp, |file| write(file, value)) -} - -/// Reads data from a reader and deserializes it -pub fn read(reader: &mut R) -> Result -where - R: Read, - T: Decode<()>, -{ - let mut len_buf = [0u8; 4]; - reader.read_exact(&mut len_buf)?; - let len = usize::try_from(u32::from_be_bytes(len_buf))?; - - let mut compressed = vec![]; - reader.read_to_end(&mut compressed)?; - let data = zstd::bulk::decompress(&compressed, len)?; - drop(compressed); - - Ok(bincode::decode_from_slice(&data, BINCODE_CONFIG)?.0) -} - -/// Reads data from a file and deserializes it -pub fn read_file(path: &Path) -> Result -where - T: Decode<()>, -{ - (|| -> Result { - let mut file = File::open(path)?; - read(&mut file) - })() - .with_context(|| format!("Failed to read file {}", path.display())) -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 1f19a41..0000000 --- a/src/main.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![doc = env!("CARGO_PKG_DESCRIPTION")] -#![warn(missing_docs)] -#![warn(clippy::missing_docs_in_private_items)] - -#[cfg(feature = "jemalloc-auto")] -extern crate minedmap_default_alloc; - -mod core; -mod io; -mod util; -mod world; - -use minedmap_nbt as nbt; -use minedmap_resource as resource; -use minedmap_types as types; - -use anyhow::Result; - -fn main() -> Result<()> { - core::cli() -} diff --git a/src/nbtdump.cpp b/src/nbtdump.cpp new file mode 100644 index 0000000..b364f41 --- /dev/null +++ b/src/nbtdump.cpp @@ -0,0 +1,55 @@ +/* + Copyright (c) 2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Buffer.hpp" +#include "GZip.hpp" +#include "Util.hpp" +#include "NBT/Tag.hpp" + +#include +#include +#include + + +int main(int argc, char *argv[]) { + using namespace MinedMap; + + if (argc != 2) { + std::fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + std::vector buffer = readGZip(argv[1]); + + Buffer nbt(buffer.data(), buffer.size()); + std::pair> tag = NBT::Tag::readNamedTag(&nbt); + if (tag.first != "") + throw std::invalid_argument("invalid root tag"); + + std::cout << *tag.second << std::endl; + + return 0; +} diff --git a/src/regiondump.cpp b/src/regiondump.cpp new file mode 100644 index 0000000..52ea31c --- /dev/null +++ b/src/regiondump.cpp @@ -0,0 +1,51 @@ +/* + Copyright (c) 2018, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "Buffer.hpp" +#include "GZip.hpp" +#include "Util.hpp" +#include "NBT/Tag.hpp" +#include "World/Region.hpp" + +#include +#include + + +int main(int argc, char *argv[]) { + using namespace MinedMap; + + if (argc != 2) { + std::fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + World::Region::visitChunks(argv[1], [&] (size_t X, size_t Z, const World::ChunkData *chunk) { + std::cout << "Chunk(" << X << ", " << Z << "): " + << chunk->getRoot() << std::endl; + }); + + return 0; +} \ No newline at end of file diff --git a/src/util.rs b/src/util.rs deleted file mode 100644 index ed07ba5..0000000 --- a/src/util.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! Utility functions and extension traits - -use crate::types::*; - -/// Extension trait for combined bit shift and mask -pub trait ShiftMask: Sized { - /// Output type of shift operation - type MaskedOutput; - - /// Apply a right shift to a value, and return both the result and the - /// bytes that were shifted out - fn shift_mask(self, shift: u8) -> (Self, Self::MaskedOutput); -} - -impl ShiftMask for u32 { - type MaskedOutput = u32; - - fn shift_mask(self, shift: u8) -> (u32, u32) { - let mask = (1 << shift) - 1; - (self >> shift, self & mask) - } -} - -impl ShiftMask for i32 { - type MaskedOutput = u32; - - #[inline] - fn shift_mask(self, shift: u8) -> (i32, u32) { - let mask = (1 << shift) - 1; - (self >> shift, (self as u32) & mask) - } -} - -/// Combines a coordinate split into region, chunk and block number to -/// a single linear coordinate -#[inline] -pub fn to_flat_coord( - region: i8, - chunk: ChunkCoord, - block: BlockCoord, -) -> i32 { - ((region as i32) << (BLOCK_BITS + CHUNK_BITS)) - | ((chunk.0 as i32) << BLOCK_BITS) - | (block.0 as i32) -} - -/// Splits a flat (linear) coordinate into region, chunk and block numbers -#[inline] -pub fn from_flat_coord(coord: i32) -> (i8, ChunkCoord, BlockCoord) { - let (region_chunk, block) = coord.shift_mask(BLOCK_BITS); - let (region, chunk) = region_chunk.shift_mask(CHUNK_BITS); - debug_assert!(i8::try_from(region).is_ok()); - (region as i8, ChunkCoord::new(chunk), BlockCoord::new(block)) -} - -/// Offsets a chunk and block coordinate pair by a number of blocks -/// -/// As the new coordinate may end up in a different region, a region offset -/// is returned together with the new chunk and block coordinates. -#[inline] -pub fn coord_offset( - chunk: ChunkCoord, - block: BlockCoord, - offset: i32, -) -> (i8, ChunkCoord, BlockCoord) { - from_flat_coord(to_flat_coord(0, chunk, block) + offset) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_coord_offset() { - const CHUNKS: i32 = CHUNKS_PER_REGION as i32; - const BLOCKS: i32 = BLOCKS_PER_CHUNK as i32; - - for chunk in ChunkX::iter() { - for block in BlockX::iter() { - assert_eq!(coord_offset(chunk, block, 0), (0, chunk, block)); - assert_eq!( - coord_offset(chunk, block, -(CHUNKS * BLOCKS)), - (-1, chunk, block) - ); - assert_eq!( - coord_offset(chunk, block, CHUNKS * BLOCKS), - (1, chunk, block) - ); - - for offset in -(CHUNKS * BLOCKS)..(CHUNKS * BLOCKS) { - let (region2, chunk2, block2) = coord_offset(chunk, block, offset); - assert!((-1..=1).contains(®ion2)); - let coord = chunk.0 as i32 * BLOCKS + block.0 as i32 + offset; - let coord2 = - ((region2 as i32 * CHUNKS) + chunk2.0 as i32) * BLOCKS + block2.0 as i32; - assert_eq!(coord2, coord); - } - } - } - } -} diff --git a/src/world/block_entity.rs b/src/world/block_entity.rs deleted file mode 100644 index 589a53c..0000000 --- a/src/world/block_entity.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! Processing of block entity data - -use bincode::{Decode, Encode}; -use minedmap_resource::{BlockFlag, BlockType}; -use serde::Serialize; - -use super::{ - de, - sign::{BlockEntitySignExt, SignText}, -}; - -/// Kind of sign block -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)] -#[serde(rename_all = "snake_case")] -pub enum SignKind { - /// Standing sign - Sign, - /// Sign attached to wall - WallSign, - /// Hanging sign - HangingSign, - /// Hanging sign attached to wall - HangingWallSign, -} - -/// Processed sign data -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)] -pub struct Sign { - /// The kind of the sign - pub kind: SignKind, - /// The material of the sign - #[serde(skip_serializing_if = "Option::is_none", default)] - pub material: Option, - /// The sign's front text - #[serde(skip_serializing_if = "SignText::is_empty", default)] - pub front_text: SignText, - /// The sign's back text - #[serde(skip_serializing_if = "SignText::is_empty", default)] - pub back_text: SignText, -} - -impl Sign { - /// Processes a [de::BlockEntitySign] into a [Sign] - fn new( - sign: &de::BlockEntitySign, - kind: SignKind, - material: Option, - data_version: u32, - ) -> Sign { - let (front_text, back_text) = sign.text(); - let front_text = front_text.decode(data_version); - let back_text = back_text.decode(data_version); - Sign { - kind, - material, - front_text, - back_text, - } - } -} - -/// Data for different kinds of [BlockEntity] -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)] -#[serde(tag = "type", rename_all = "snake_case")] -pub enum BlockEntityData { - /// A sign block - Sign(Sign), -} - -/// A processed block entity -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, Serialize)] -pub struct BlockEntity { - /// Global X coordinate - pub x: i32, - /// Global Y coordinate - pub y: i32, - /// Global Z coordinate - pub z: i32, - /// Entity data - #[serde(flatten)] - pub data: BlockEntityData, -} - -impl BlockEntity { - /// Processes a [de::BlockEntity] into a [BlockEntity] - pub fn new( - entity: &de::BlockEntity, - block_type: Option<&BlockType>, - data_version: u32, - ) -> Option { - let wall_sign = block_type - .map(|block_type| block_type.block_color.is(BlockFlag::WallSign)) - .unwrap_or_default(); - let (kind, sign) = match (&entity.data, wall_sign) { - (de::BlockEntityData::Sign(sign), false) => (SignKind::Sign, sign), - (de::BlockEntityData::Sign(sign), true) => (SignKind::WallSign, sign), - (de::BlockEntityData::HangingSign(sign), false) => (SignKind::HangingSign, sign), - (de::BlockEntityData::HangingSign(sign), true) => (SignKind::HangingWallSign, sign), - (de::BlockEntityData::Other, _) => return None, - }; - let material = block_type - .as_ref() - .and_then(|block_type| block_type.sign_material.as_ref()); - let data = BlockEntityData::Sign(Sign::new(sign, kind, material.cloned(), data_version)); - - Some(BlockEntity { - x: entity.x, - y: entity.y, - z: entity.z, - data, - }) - } -} diff --git a/src/world/chunk.rs b/src/world/chunk.rs deleted file mode 100644 index aadf882..0000000 --- a/src/world/chunk.rs +++ /dev/null @@ -1,443 +0,0 @@ -//! Higher-level interfaces to chunk data -//! -//! The data types in this module attempt to provide interfaces abstracting -//! over different data versions as much as possible. - -use std::{ - collections::{BTreeMap, btree_map}, - iter::{self, FusedIterator}, -}; - -use anyhow::{Context, Result, bail}; - -use super::{block_entity::BlockEntity, de, section::*}; -use crate::{ - resource::{BiomeTypes, BlockType, BlockTypes}, - types::*, - util::{self, ShiftMask}, -}; - -/// Version-specific part of [Chunk] -#[derive(Debug)] -pub enum ChunkInner<'a> { - /// Minecraft v1.18+ chunk with biome data moved into sections - V1_18 { - /// Section data - section_map: BTreeMap, BiomesV1_18<'a>, BlockLight<'a>)>, - }, - /// Minecraft v1.13+ chunk - /// - /// Block data is stored in an indexed format with variable bit width - /// (depending on the total numer of distinct block types used in a - /// section), and a palette mapping these indices to namespaced - /// block IDs - V1_13 { - /// Section data - section_map: BTreeMap, BlockLight<'a>)>, - /// Biome data - biomes: BiomesV0<'a>, - }, - /// Original pre-1.13 chunk - /// - /// The original chunk format with fixed 8-bit numeric block IDs - V0 { - /// Section data - section_map: BTreeMap, BlockLight<'a>)>, - /// Biome data - biomes: BiomesV0<'a>, - }, - /// Unpopulated chunk without any block data - Empty, -} - -/// Chunk data structure wrapping a [de::Chunk] for convenient access to -/// block and biome data -#[derive(Debug)] -pub struct Chunk<'a> { - /// Version-specific data - inner: ChunkInner<'a>, - /// Unprocessed block entities - block_entities: &'a Vec, - /// Chunk data version - data_version: u32, -} - -impl<'a> Chunk<'a> { - /// Creates a new [Chunk] from a deserialized [de::Chunk] - pub fn new( - data: &'a de::Chunk, - block_types: &'a BlockTypes, - biome_types: &'a BiomeTypes, - ) -> Result<(Self, bool)> { - let data_version = data.data_version.unwrap_or_default(); - - let ((inner, has_unknown), block_entities) = match &data.chunk { - de::ChunkVariant::V1_18 { - sections, - block_entities, - } => ( - Self::new_v1_18(data_version, sections, block_types, biome_types)?, - block_entities, - ), - de::ChunkVariant::V0 { level } => ( - Self::new_v0(data_version, level, block_types, biome_types)?, - &level.tile_entities, - ), - }; - - Ok(( - Chunk { - inner, - block_entities, - data_version, - }, - has_unknown, - )) - } - - /// [Chunk::new] implementation for Minecraft v1.18+ chunks - fn new_v1_18( - data_version: u32, - sections: &'a Vec, - block_types: &'a BlockTypes, - biome_types: &'a BiomeTypes, - ) -> Result<(ChunkInner<'a>, bool)> { - let mut section_map = BTreeMap::new(); - let mut has_unknown = false; - - for section in sections { - match §ion.section { - de::SectionV1_18Variant::V1_18 { - block_states, - biomes, - block_light, - } => { - let (loaded_section, unknown_blocks) = SectionV1_13::new( - data_version, - block_states.data.as_deref(), - &block_states.palette, - block_types, - ) - .with_context(|| format!("Failed to load section at Y={}", section.y))?; - has_unknown |= unknown_blocks; - - let (loaded_biomes, unknown_biomes) = - BiomesV1_18::new(biomes.data.as_deref(), &biomes.palette, biome_types) - .with_context(|| { - format!("Failed to load section biomes at Y={}", section.y) - })?; - has_unknown |= unknown_biomes; - - section_map.insert( - SectionY(section.y), - ( - loaded_section, - loaded_biomes, - BlockLight::new(block_light.as_deref()).with_context(|| { - format!("Failed to load section block light at Y={}", section.y) - })?, - ), - ); - } - de::SectionV1_18Variant::Empty {} => {} - }; - } - - let chunk = ChunkInner::V1_18 { section_map }; - Ok((chunk, has_unknown)) - } - - /// [Chunk::new] implementation for all pre-1.18 chunk variants - fn new_v0( - data_version: u32, - level: &'a de::LevelV0, - block_types: &'a BlockTypes, - biome_types: &'a BiomeTypes, - ) -> Result<(ChunkInner<'a>, bool)> { - let mut section_map_v1_13 = BTreeMap::new(); - let mut section_map_v0 = BTreeMap::new(); - let mut has_unknown = false; - - for section in &level.sections { - let block_light = - BlockLight::new(section.block_light.as_deref()).with_context(|| { - format!("Failed to load section block light at Y={}", section.y) - })?; - match §ion.section { - de::SectionV0Variant::V1_13 { - block_states, - palette, - } => { - let (loaded_section, unknown_blocks) = - SectionV1_13::new(data_version, Some(block_states), palette, block_types) - .with_context(|| format!("Failed to load section at Y={}", section.y))?; - has_unknown |= unknown_blocks; - - section_map_v1_13 - .insert(SectionY(section.y.into()), (loaded_section, block_light)); - } - de::SectionV0Variant::V0 { blocks, data } => { - section_map_v0.insert( - SectionY(section.y.into()), - ( - SectionV0::new(blocks, data, block_types).with_context(|| { - format!("Failed to load section at Y={}", section.y) - })?, - block_light, - ), - ); - } - de::SectionV0Variant::Empty {} => {} - } - } - - let biomes = BiomesV0::new(level.biomes.as_ref(), biome_types); - let chunk = match (section_map_v1_13.is_empty(), section_map_v0.is_empty()) { - (true, true) => ChunkInner::Empty, - (false, true) => ChunkInner::V1_13 { - section_map: section_map_v1_13, - biomes: biomes?, - }, - (true, false) => ChunkInner::V0 { - section_map: section_map_v0, - biomes: biomes?, - }, - (false, false) => { - bail!("Mixed section versions"); - } - }; - - Ok((chunk, has_unknown)) - } - - /// Returns true if the chunk does not contain any sections - pub fn is_empty(&self) -> bool { - match &self.inner { - ChunkInner::V1_18 { section_map } => section_map.is_empty(), - ChunkInner::V1_13 { section_map, .. } => section_map.is_empty(), - ChunkInner::V0 { section_map, .. } => section_map.is_empty(), - ChunkInner::Empty => true, - } - } - - /// Returns an interator over the chunk's sections and their Y coordinates - pub fn sections(&self) -> SectionIter { - use SectionIterInner::*; - SectionIter { - inner: match &self.inner { - ChunkInner::V1_18 { section_map } => V1_18 { - iter: section_map.iter(), - }, - ChunkInner::V1_13 { - section_map, - biomes, - } => V1_13 { - iter: section_map.iter(), - biomes, - }, - ChunkInner::V0 { - section_map, - biomes, - } => V0 { - iter: section_map.iter(), - biomes, - }, - ChunkInner::Empty => Empty, - }, - } - } - - /// Returns the section at a [SectionY] coordinate - fn section_at(&self, y: SectionY) -> Option<&dyn Section> { - match &self.inner { - ChunkInner::V1_18 { section_map } => section_map - .get(&y) - .map(|(section, _, _)| -> &dyn Section { section }), - ChunkInner::V1_13 { section_map, .. } => section_map - .get(&y) - .map(|(section, _)| -> &dyn Section { section }), - ChunkInner::V0 { section_map, .. } => section_map - .get(&y) - .map(|(section, _)| -> &dyn Section { section }), - ChunkInner::Empty => None, - } - } - - /// Returns the [BlockType] at a given coordinate - fn block_type_at(&self, y: SectionY, coords: SectionBlockCoords) -> Result> { - let Some(section) = self.section_at(y) else { - return Ok(None); - }; - section.block_at(coords) - } - - /// Returns the [BlockType] at the coordinates of a [de::BlockEntity] - fn block_type_at_block_entity( - &self, - block_entity: &de::BlockEntity, - ) -> Result> { - let x: BlockX = util::from_flat_coord(block_entity.x).2; - let z: BlockZ = util::from_flat_coord(block_entity.z).2; - let (section_y, block_y) = block_entity.y.shift_mask(BLOCK_BITS); - - let coords = SectionBlockCoords { - xz: LayerBlockCoords { x, z }, - y: BlockY::new(block_y), - }; - - self.block_type_at(SectionY(section_y), coords) - } - - /// Processes all of the chunk's block entities - pub fn block_entities(&self) -> Result> { - let entities: Vec> = self - .block_entities - .iter() - .map(|block_entity| { - let block_type = self.block_type_at_block_entity(block_entity)?; - Ok(BlockEntity::new( - block_entity, - block_type, - self.data_version, - )) - }) - .collect::>()?; - Ok(entities.into_iter().flatten().collect()) - } -} - -/// Reference to block, biome and block light data of a section -#[derive(Debug, Clone, Copy)] -pub struct SectionIterItem<'a> { - /// The Y coordinate of the section - pub y: SectionY, - /// Section block data - pub section: &'a dyn Section, - /// Section biome data - pub biomes: &'a dyn Biomes, - /// Section block light data - pub block_light: BlockLight<'a>, -} - -/// Helper trait to specify section iterator trait bounds -trait SectionIterTrait<'a>: - Iterator> + DoubleEndedIterator + ExactSizeIterator + FusedIterator -{ -} - -impl<'a, T> SectionIterTrait<'a> for T where - T: Iterator> - + DoubleEndedIterator - + ExactSizeIterator - + FusedIterator -{ -} - -/// Inner data structure of [SectionIter] -#[derive(Debug, Clone)] -enum SectionIterInner<'a> { - /// Iterator over sections of [ChunkInner::V1_18] - V1_18 { - /// Inner iterator into section map - iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BiomesV1_18<'a>, BlockLight<'a>)>, - }, - /// Iterator over sections of [ChunkInner::V1_13] - V1_13 { - /// Inner iterator into section map - iter: btree_map::Iter<'a, SectionY, (SectionV1_13<'a>, BlockLight<'a>)>, - /// Chunk biome data - biomes: &'a BiomesV0<'a>, - }, - /// Iterator over sections of [ChunkInner::V0] - V0 { - /// Inner iterator into section map - iter: btree_map::Iter<'a, SectionY, (SectionV0<'a>, BlockLight<'a>)>, - /// Chunk biome data - biomes: &'a BiomesV0<'a>, - }, - /// Empty iterator over an unpopulated chunk ([ChunkInner::Empty]) - Empty, -} - -/// Iterator over the sections of a [Chunk] -#[derive(Debug, Clone)] -pub struct SectionIter<'a> { - /// Inner iterator enum - inner: SectionIterInner<'a>, -} - -impl<'a> SectionIter<'a> { - /// Helper to run a closure on the inner section iterator - fn with_iter(&mut self, f: F) -> T - where - F: FnOnce(&mut dyn SectionIterTrait<'a>) -> T, - { - match &mut self.inner { - SectionIterInner::V1_18 { iter } => f(&mut iter.map( - |(&y, (section, biomes, block_light))| SectionIterItem { - y, - section, - biomes, - block_light: *block_light, - }, - )), - SectionIterInner::V1_13 { iter, biomes } => f(&mut iter.map( - |(&y, (section, block_light))| SectionIterItem { - y, - section, - biomes: *biomes, - block_light: *block_light, - }, - )), - SectionIterInner::V0 { iter, biomes } => f(&mut iter.map( - |(&y, (section, block_light))| SectionIterItem { - y, - section, - biomes: *biomes, - block_light: *block_light, - }, - )), - SectionIterInner::Empty => f(&mut iter::empty()), - } - } -} - -impl<'a> Iterator for SectionIter<'a> { - type Item = SectionIterItem<'a>; - - fn next(&mut self) -> Option { - self.with_iter(|iter| iter.next()) - } - - fn size_hint(&self) -> (usize, Option) { - match &self.inner { - SectionIterInner::V1_18 { iter } => iter.size_hint(), - SectionIterInner::V1_13 { iter, .. } => iter.size_hint(), - SectionIterInner::V0 { iter, .. } => iter.size_hint(), - SectionIterInner::Empty => (0, Some(0)), - } - } - - fn last(mut self) -> Option { - self.next_back() - } -} - -impl DoubleEndedIterator for SectionIter<'_> { - fn next_back(&mut self) -> Option { - self.with_iter(|iter| iter.next_back()) - } -} - -impl ExactSizeIterator for SectionIter<'_> { - fn len(&self) -> usize { - match &self.inner { - SectionIterInner::V1_18 { iter } => iter.len(), - SectionIterInner::V1_13 { iter, .. } => iter.len(), - SectionIterInner::V0 { iter, .. } => iter.len(), - SectionIterInner::Empty => 0, - } - } -} - -impl FusedIterator for SectionIter<'_> {} diff --git a/src/world/de.rs b/src/world/de.rs deleted file mode 100644 index 0a4b4b6..0000000 --- a/src/world/de.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! Data structures used to deserialize Minecraft save data - -use serde::Deserialize; - -use super::text_value::TextValue; - -/// Element of the `palette` list of 1.18+ [block states](BlockStatesV1_18) -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct BlockStatePaletteEntry { - /// Block type ID - pub name: String, -} - -/// 1.18+ `block_states` element found in a [section](SectionV1_18) -#[derive(Debug, Deserialize)] -pub struct BlockStatesV1_18 { - /// Palette of block types, indexed by block data - pub palette: Vec, - /// Block data - pub data: Option, -} - -/// 1.18+ `biomes` element found in a [section](SectionV1_18) -#[derive(Debug, Deserialize)] -pub struct BiomesV1_18 { - /// Palette of biome types, indexed by biome data - pub palette: Vec, - /// Biome data - pub data: Option, -} - -/// Variable part of a [SectionV1_18] -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum SectionV1_18Variant { - /// Populated 1.18+ section - V1_18 { - /// Block type data - block_states: BlockStatesV1_18, - /// Biome data - biomes: BiomesV1_18, - /// Block light data - #[serde(rename = "BlockLight")] - block_light: Option, - }, - /// Empty section - Empty {}, -} - -/// Element of the 1.18+ `sections` list found in a [Chunk] -#[derive(Debug, Deserialize)] -pub struct SectionV1_18 { - /// Y coordinate - #[serde(rename = "Y")] - pub y: i32, - /// Variable part of section - #[serde(flatten)] - pub section: SectionV1_18Variant, -} - -/// Version-specific part of a pre-1.18 [Section](SectionV0) -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum SectionV0Variant { - /// v1.13+ data - #[serde(rename_all = "PascalCase")] - V1_13 { - /// Block data - block_states: fastnbt::LongArray, - /// Block type palette, indexed by block data - palette: Vec, - }, - /// Pre-1.13 data - #[serde(rename_all = "PascalCase")] - V0 { - /// Block type data - blocks: fastnbt::ByteArray, - /// Block damage / subtype data - data: fastnbt::ByteArray, - }, - /// Empty section - Empty {}, -} - -/// Pre-1.18 section element found in the [Level](LevelV0) compound -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct SectionV0 { - /// Y coordinate - pub y: i8, - /// Block light data - pub block_light: Option, - /// Version-specific data - #[serde(flatten)] - pub section: SectionV0Variant, -} - -/// Pre-1.18 biome fields found in the [Level](LevelV0) compound -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum BiomesV0 { - /// Data for Minecraft versions storing biome data as an IntArray - IntArray(fastnbt::IntArray), - /// Data for Minecraft versions storing biome data as an ByteArray - ByteArray(fastnbt::ByteArray), -} - -/// Front/back text of a Minecraft 1.20+ sign block entry -#[derive(Debug, Deserialize)] -pub struct BlockEntitySignV1_20Text { - /// Lines of sign text - pub messages: Vec, - /// Default text color - pub color: Option, -} - -/// A sign (standing or hanging) block entity -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum BlockEntitySign { - /// Pre-1.20 sign block entity - /// - /// Pre-1.20 signs only have front text. - #[serde(rename_all = "PascalCase")] - V0 { - /// Line 1 of the sign text - text1: TextValue, - /// Line 2 of the sign text - text2: TextValue, - /// Line 3 of the sign text - text3: TextValue, - /// Line 4 of the sign text - text4: TextValue, - /// Default text color - color: Option, - }, - /// 1.20+ sign block entity - V1_20 { - /// The sign's front text - front_text: BlockEntitySignV1_20Text, - /// The sign's back text - back_text: BlockEntitySignV1_20Text, - }, -} - -/// Data for different kinds of block entities -#[derive(Debug, Deserialize)] -#[serde(tag = "id")] -pub enum BlockEntityData { - /// Regular sign - /// - /// This includes standing signs and signs attached to the side of blocks - #[serde(rename = "minecraft:sign", alias = "minecraft:standing_sign")] - Sign(BlockEntitySign), - /// Hanging sign - #[serde(rename = "minecraft:hanging_sign")] - HangingSign(BlockEntitySign), - /// Other block entity types not handled by MinedMap - #[serde(other)] - Other, -} - -/// A block entity -/// -/// Block entities were called tile entities pre-1.18 -#[derive(Debug, Deserialize)] -pub struct BlockEntity { - /// Entity global X coordinate - pub x: i32, - /// Entity global Y coordinate - pub y: i32, - /// Entity global Z coordinate - pub z: i32, - /// Kind-specific entity data - #[serde(flatten)] - pub data: BlockEntityData, -} - -/// `Level` compound element found in pre-1.18 [chunks](Chunk) -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct LevelV0 { - /// Section data - #[serde(default)] - pub sections: Vec, - /// Biome data - pub biomes: Option, - /// List of block entities - #[serde(default)] - pub tile_entities: Vec, -} - -/// Version-specific part of a [Chunk] compound -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum ChunkVariant { - /// 1.18+ chunk data - V1_18 { - /// List of chunk sections - sections: Vec, - /// List of block entities - #[serde(default)] - block_entities: Vec, - }, - /// Pre-1.18 chunk data - #[serde(rename_all = "PascalCase")] - V0 { - /// `Level` field of the chunk - level: LevelV0, - }, -} - -/// Toplevel compound element of a Minecraft chunk -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct Chunk { - /// The data version of the chunk - pub data_version: Option, - /// Version-specific chunk data - #[serde(flatten)] - pub chunk: ChunkVariant, -} - -/// `Data` compound element of level.dat -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct LevelDatData { - /// X coordinate of spawn point for new players - pub spawn_x: i32, - /// Z coordinate of spawn point for new players - pub spawn_z: i32, -} - -/// Toplevel compound element of level.dat -#[derive(Debug, Deserialize)] -#[serde(rename_all = "PascalCase")] -pub struct LevelDat { - /// The `Data` field - pub data: LevelDatData, -} diff --git a/src/world/layer.rs b/src/world/layer.rs deleted file mode 100644 index deb4b48..0000000 --- a/src/world/layer.rs +++ /dev/null @@ -1,194 +0,0 @@ -//! Functions to search the "top" layer of a chunk - -use std::num::NonZeroU16; - -use anyhow::{Context, Result}; -use bincode::{Decode, Encode}; -use indexmap::IndexSet; - -use super::chunk::{Chunk, SectionIterItem}; -use crate::{ - resource::{Biome, BlockColor, BlockFlag}, - types::*, -}; - -/// Height (Y coordinate) of a block -#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)] -pub struct BlockHeight(pub i32); - -impl BlockHeight { - /// Constructs a new [BlockHeight] from section and block Y indices - /// - /// Returns an error if the resulting coordindate does not fit into - /// an [i32]. - pub fn new(section: SectionY, block: BlockY) -> Result { - let height = section - .0 - .checked_mul(BLOCKS_PER_CHUNK as i32) - .and_then(|y| y.checked_add_unsigned(block.0.into())) - .context("Block height out of bounds")?; - Ok(BlockHeight(height)) - } -} - -/// Array optionally storing a [BlockColor] for each coordinate of a chunk -pub type BlockArray = LayerBlockArray>; - -/// Array optionally storing a biome index for each coordinate of a chunk -/// -/// The entries refer to a biome list generated with the top layer data. -/// Indices are stored incremented by 1 to allow using a [NonZeroU16]. -pub type BiomeArray = LayerBlockArray>; - -/// Array storing a block light value for each coordinate for a chunk -pub type BlockLightArray = LayerBlockArray; - -/// Array optionally storing a depth value for each coordinate for a chunk -pub type DepthArray = LayerBlockArray>; - -/// References to LayerData entries for a single coordinate pair -struct LayerEntry<'a> { - /// The block type of the referenced entry - block: &'a mut Option, - /// The biome type of the referenced entry - biome: &'a mut Option, - /// The block light of the referenced entry - block_light: &'a mut u8, - /// The depth value of the referenced entry - depth: &'a mut Option, -} - -impl LayerEntry<'_> { - /// Returns true if the entry has not been filled yet (no opaque block has been encountered) - /// - /// The depth value is filled separately when a non-water block is encountered after the block type - /// has already been filled. - fn is_empty(&self) -> bool { - self.block.is_none() - } - - /// Returns true if the entry has been filled including its depth (an opaque non-water block has been - /// encountered) - fn done(&self) -> bool { - self.depth.is_some() - } - - /// Fills in the LayerEntry - /// - /// Checks whether the passed coordinates point at an opaque or non-water block and - /// fills in the entry accordingly. Returns true when the block has been filled including its depth. - fn fill( - &mut self, - biome_list: &mut IndexSet, - section: SectionIterItem, - coords: SectionBlockCoords, - ) -> Result { - let Some(block_type) = section - .section - .block_at(coords)? - .filter(|block_type| block_type.block_color.is(BlockFlag::Opaque)) - else { - if self.is_empty() { - *self.block_light = section.block_light.block_light_at(coords); - } - - return Ok(false); - }; - - if self.is_empty() { - *self.block = Some(block_type.block_color); - - let biome = section.biomes.biome_at(section.y, coords)?; - let (biome_index, _) = biome_list.insert_full(*biome); - *self.biome = NonZeroU16::new( - (biome_index + 1) - .try_into() - .expect("biome index not in range"), - ); - } - - if block_type.block_color.is(BlockFlag::Water) { - return Ok(false); - } - - let height = BlockHeight::new(section.y, coords.y)?; - *self.depth = Some(height); - - Ok(true) - } -} - -/// Top layer data -/// -/// A LayerData stores block type, biome, block light and depth data for -/// each coordinate of a chunk. -#[derive(Debug, Default)] -pub struct LayerData { - /// Block type data - pub blocks: Box, - /// Biome data - pub biomes: Box, - /// Block light data - pub block_light: Box, - /// Depth data - pub depths: Box, -} - -impl LayerData { - /// Builds a [LayerEntry] referencing the LayerData at a given coordinate pair - fn entry(&mut self, coords: LayerBlockCoords) -> LayerEntry { - LayerEntry { - block: &mut self.blocks[coords], - biome: &mut self.biomes[coords], - block_light: &mut self.block_light[coords], - depth: &mut self.depths[coords], - } - } -} - -/// Fills in a [LayerData] with the information of the chunk's top -/// block layer -/// -/// For each (X, Z) coordinate pair, the topmost opaque block is -/// determined as the block that should be visible on the rendered -/// map. For water blocks, the height of the first non-water block -/// is additionally filled in as the water depth (the block height is -/// used as depth otherwise). -pub fn top_layer(biome_list: &mut IndexSet, chunk: &Chunk) -> Result> { - use BLOCKS_PER_CHUNK as N; - - if chunk.is_empty() { - return Ok(None); - } - - let mut done = 0; - let mut ret = LayerData::default(); - - for section in chunk.sections().rev() { - for y in BlockY::iter().rev() { - for z in BlockZ::iter() { - for x in BlockX::iter() { - let xz = LayerBlockCoords { x, z }; - - let mut entry = ret.entry(xz); - if entry.done() { - continue; - } - - let coords = SectionBlockCoords { xz, y }; - if !entry.fill(biome_list, section, coords)? { - continue; - } - - assert!(entry.done()); - done += 1; - if done == N * N { - break; - } - } - } - } - } - - Ok(Some(ret)) -} diff --git a/src/world/mod.rs b/src/world/mod.rs deleted file mode 100644 index 8a2e9be..0000000 --- a/src/world/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Data structures describing Minecraft save data - -pub mod block_entity; -pub mod chunk; -pub mod de; -pub mod layer; -pub mod section; -pub mod sign; -pub mod text_value; diff --git a/src/world/section.rs b/src/world/section.rs deleted file mode 100644 index dc5c9a6..0000000 --- a/src/world/section.rs +++ /dev/null @@ -1,405 +0,0 @@ -//! Higher-level interfaces to section data -//! -//! The data types in this module attempt to provide interfaces abstracting -//! over different data versions as much as possible. - -use std::fmt::Debug; - -use anyhow::{Context, Result, bail}; -use num_integer::div_rem; -use tracing::debug; - -use super::de; -use crate::{ - resource::{Biome, BiomeTypes, BlockType, BlockTypes}, - types::*, -}; - -use BLOCKS_PER_CHUNK as N; -/// Maximum height of pre-1.18 levels -const HEIGHT: usize = 256; -/// Number of biome entries per chunk in each direction -const BN: usize = N >> 2; -/// Pre-1.18 height of level measured in 4-block spans (resolution of 1.15+ biome data) -const BHEIGHT: usize = HEIGHT >> 2; - -/// Determine the number of bits required for indexing into a palette of a given length -/// -/// This is basically a base-2 logarithm, with clamping to a minimum value and -/// check against a maximum value. If the result would be greater than the passed -/// `max` value, [None] is returned. -fn palette_bits(len: usize, min: u8, max: u8) -> Option { - let mut bits = min; - while (1 << bits) < len { - bits += 1; - - if bits > max { - return None; - } - } - - Some(bits) -} - -/// Trait for common functions of [SectionV1_13] and [SectionV0] -pub trait Section: Debug { - /// Returns the [BlockType] at a coordinate tuple inside the section - fn block_at(&self, coords: SectionBlockCoords) -> Result>; -} - -/// Minecraft v1.13+ section block data -#[derive(Debug)] -pub struct SectionV1_13<'a> { - /// Packed block type data - block_states: Option<&'a [i64]>, - /// List of block types indexed by entries encoded in *block_states* - palette: Vec>, - /// Number of bits per block in *block_states* - bits: u8, - /// Set to true if packed block entries in *block_states* are aligned to i64 - /// - /// In older data formats, entries are unaligned and a single block can span - /// two i64 entries. - aligned_blocks: bool, -} - -impl<'a> SectionV1_13<'a> { - /// Constructs a new [SectionV1_13] from deserialized data structures - /// - /// The block IDs in the section's palette are resolved to their [BlockType]s - /// to allow for faster lookup later. - pub fn new( - data_version: u32, - block_states: Option<&'a [i64]>, - palette: &'a [de::BlockStatePaletteEntry], - block_types: &'a BlockTypes, - ) -> Result<(Self, bool)> { - let aligned_blocks = data_version >= 2529; - - let bits = palette_bits(palette.len(), 4, 12).context("Unsupported block palette size")?; - - if let Some(block_states) = block_states { - let expected_length = if aligned_blocks { - let blocks_per_word = 64 / bits as usize; - 4096usize.div_ceil(blocks_per_word) - } else { - 64 * bits as usize - }; - if block_states.len() != expected_length { - bail!("Invalid section block data"); - } - } - - let mut has_unknown = false; - - let palette_types = palette - .iter() - .map(|entry| { - let block_type = block_types.get(&entry.name); - if block_type.is_none() { - debug!("Unknown block type: {}", entry.name); - has_unknown = true; - } - block_type - }) - .collect(); - - Ok(( - Self { - block_states, - palette: palette_types, - bits, - aligned_blocks, - }, - has_unknown, - )) - } - - /// Looks up the block type palette index at the given coordinates - fn palette_index_at(&self, coords: SectionBlockCoords) -> usize { - let Some(block_states) = self.block_states else { - return 0; - }; - - let bits = self.bits as usize; - let mask = (1 << bits) - 1; - - let offset = coords.offset(); - - let shifted = if self.aligned_blocks { - let blocks_per_word = 64 / bits; - let (word, shift) = div_rem(offset, blocks_per_word); - block_states[word] as u64 >> (shift * bits) - } else { - let bit_offset = offset * bits; - let (word, bit_shift) = div_rem(bit_offset, 64); - - let mut tmp = (block_states[word] as u64) >> bit_shift; - if bit_shift + bits > 64 { - tmp |= (block_states[word + 1] as u64) << (64 - bit_shift); - } - tmp - }; - - (shifted & mask) as usize - } -} - -impl Section for SectionV1_13<'_> { - fn block_at(&self, coords: SectionBlockCoords) -> Result> { - let index = self.palette_index_at(coords); - Ok(*self - .palette - .get(index) - .context("Palette index out of bounds")?) - } -} - -/// Pre-1.13 section block data -#[derive(Debug)] -pub struct SectionV0<'a> { - /// Block type data - /// - /// Each i8 entry corresponds to a block in the 16x16x16 section - blocks: &'a [i8], - /// Block damage/subtype data - /// - /// Uses 4 bits for each block in the 16x16x16 section - data: &'a [i8], - /// Used to look up block type IDs - block_types: &'a BlockTypes, -} - -impl<'a> SectionV0<'a> { - /// Constructs a new [SectionV0] from deserialized data structures - pub fn new(blocks: &'a [i8], data: &'a [i8], block_types: &'a BlockTypes) -> Result { - if blocks.len() != N * N * N { - bail!("Invalid section block data"); - } - if data.len() != N * N * N / 2 { - bail!("Invalid section extra data"); - } - - Ok(SectionV0 { - blocks, - data, - block_types, - }) - } -} - -impl Section for SectionV0<'_> { - fn block_at(&self, coords: SectionBlockCoords) -> Result> { - let offset = coords.offset(); - let block = self.blocks[offset] as u8; - - let (data_offset, data_nibble) = div_rem(offset, 2); - let data_byte = self.data[data_offset] as u8; - let data = if data_nibble == 1 { - data_byte >> 4 - } else { - data_byte & 0xf - }; - - Ok(self.block_types.get_legacy(block, data)) - } -} - -/// Trait for common functions of [BiomesV1_18] and [BiomesV0] -pub trait Biomes: Debug { - /// Returns the [Biome] at a coordinate tuple inside the chunk - fn biome_at(&self, section: SectionY, coords: SectionBlockCoords) -> Result<&Biome>; -} - -/// Minecraft v1.18+ section biome data -/// -/// The biome data is part of the section structure in Minecraft v1.18+, with -/// the biomes laid out as an array of indices into a palette, similar to the -/// v1.13+ block data. -#[derive(Debug)] -pub struct BiomesV1_18<'a> { - /// Packed biome data - /// - /// Each entry specifies the biome of a 4x4x4 block area. - /// - /// Unlike block type data in [SectionV1_13], biome data is always aligned - /// to whole i64 values. - biomes: Option<&'a [i64]>, - /// Biome palette indexed by entries encoded in *biomes* - palette: Vec<&'a Biome>, - /// Number of bits used for each entry in *biomes* - bits: u8, -} - -impl<'a> BiomesV1_18<'a> { - /// Constructs a new [BiomesV1_18] from deserialized data structures - pub fn new( - biomes: Option<&'a [i64]>, - palette: &'a [String], - biome_types: &'a BiomeTypes, - ) -> Result<(Self, bool)> { - let bits = palette_bits(palette.len(), 1, 6).context("Unsupported block palette size")?; - - if let Some(biomes) = biomes { - let biomes_per_word = 64 / bits as usize; - let expected_length = 64usize.div_ceil(biomes_per_word); - if biomes.len() != expected_length { - bail!("Invalid section biome data"); - } - } - - let mut has_unknown = false; - - let palette_types = palette - .iter() - .map(|entry| { - biome_types.get(entry).unwrap_or_else(|| { - debug!("Unknown biome type: {}", entry); - has_unknown = true; - biome_types.get_fallback() - }) - }) - .collect(); - - Ok(( - BiomesV1_18 { - biomes, - palette: palette_types, - bits, - }, - has_unknown, - )) - } - - /// Looks up the block type palette index at the given coordinates - fn palette_index_at(&self, coords: SectionBlockCoords) -> usize { - let Some(biomes) = self.biomes else { - return 0; - }; - - let bits = self.bits as usize; - let mask = (1 << bits) - 1; - - let x = (coords.xz.x.0 >> 2) as usize; - let y = (coords.y.0 >> 2) as usize; - let z = (coords.xz.z.0 >> 2) as usize; - let offset = BN * BN * y + BN * z + x; - - let blocks_per_word = 64 / bits; - let (word, shift) = div_rem(offset, blocks_per_word); - let shifted = biomes[word] as u64 >> (shift * bits); - - (shifted & mask) as usize - } -} - -impl Biomes for BiomesV1_18<'_> { - fn biome_at(&self, _section: SectionY, coords: SectionBlockCoords) -> Result<&Biome> { - let index = self.palette_index_at(coords); - Ok(*self - .palette - .get(index) - .context("Palette index out of bounds")?) - } -} - -/// Pre-v1.18 section biome data variants -/// -/// There are a 3 formats for biome data that were used in -/// different pre-v1.18 Minecraft versions -#[derive(Debug)] -enum BiomesV0Data<'a> { - /// Biome data stored as IntArray in 1.15+ format - /// - /// Minecraft 1.15 switched to 3-dimensional biome information, but reduced - /// the resolution to only use one entry for every 4x4x4 block area. - IntArrayV15(&'a fastnbt::IntArray), - /// Biome data stored as IntArray in some pre-1.15 versions - IntArrayV0(&'a fastnbt::IntArray), - /// Biome data stored as ByteArray in some pre-1.15 versions - ByteArray(&'a fastnbt::ByteArray), -} - -/// Pre-v1.18 section biome data -#[derive(Debug)] -pub struct BiomesV0<'a> { - /// Biome data from save data - data: BiomesV0Data<'a>, - /// Used to look up biome IDs - biome_types: &'a BiomeTypes, -} - -impl<'a> BiomesV0<'a> { - /// Constructs a new [BiomesV0] from deserialized data structures - pub fn new(biomes: Option<&'a de::BiomesV0>, biome_types: &'a BiomeTypes) -> Result { - let data = match biomes { - Some(de::BiomesV0::IntArray(data)) if data.len() == BN * BN * BHEIGHT => { - BiomesV0Data::IntArrayV15(data) - } - Some(de::BiomesV0::IntArray(data)) if data.len() == N * N => { - BiomesV0Data::IntArrayV0(data) - } - Some(de::BiomesV0::ByteArray(data)) if data.len() == N * N => { - BiomesV0Data::ByteArray(data) - } - _ => bail!("Invalid biome data"), - }; - Ok(BiomesV0 { data, biome_types }) - } -} - -impl Biomes for BiomesV0<'_> { - fn biome_at(&self, section: SectionY, coords: SectionBlockCoords) -> Result<&Biome> { - let id = match self.data { - BiomesV0Data::IntArrayV15(data) => { - let LayerBlockCoords { x, z } = coords.xz; - let y = section - .0 - .checked_mul(BLOCKS_PER_CHUNK as i32) - .and_then(|y| y.checked_add_unsigned(coords.y.0.into())) - .filter(|&height| height >= 0 && (height as usize) < HEIGHT) - .context("Y coordinate out of range")? as usize; - let offset = (y >> 2) * BN * BN + (z.0 >> 2) as usize * BN + (x.0 >> 2) as usize; - let id = data[offset] as u32; - id.try_into().context("Biome index out of range")? - } - BiomesV0Data::IntArrayV0(data) => { - let id = data[coords.xz.offset()] as u32; - id.try_into().context("Biome index out of range")? - } - BiomesV0Data::ByteArray(data) => data[coords.xz.offset()] as u8, - }; - Ok(self - .biome_types - .get_legacy(id) - .unwrap_or(self.biome_types.get_fallback())) - } -} - -/// Wrapper around chunk block light data array -#[derive(Debug, Clone, Copy)] -pub struct BlockLight<'a>(Option<&'a [i8]>); - -impl<'a> BlockLight<'a> { - /// Creates a new [BlockLight], checking validity - pub fn new(block_light: Option<&'a [i8]>) -> Result { - if let Some(block_light) = block_light { - if block_light.len() != N * N * N / 2 { - bail!("Invalid section block light data"); - } - } - Ok(BlockLight(block_light)) - } - - /// Returns the block light value at the given coordinates - pub fn block_light_at(&self, coords: SectionBlockCoords) -> u8 { - let Some(block_light) = self.0 else { - return 0; - }; - - let (offset, nibble) = div_rem(coords.offset(), 2); - let byte = block_light[offset] as u8; - - if nibble == 1 { byte >> 4 } else { byte & 0xf } - } -} diff --git a/src/world/sign.rs b/src/world/sign.rs deleted file mode 100644 index 8e4e670..0000000 --- a/src/world/sign.rs +++ /dev/null @@ -1,158 +0,0 @@ -//! Processing of sign text - -use std::fmt::Display; - -use bincode::{Decode, Encode}; -use minedmap_resource::Color; -use serde::Serialize; - -use super::{ - de, - text_value::{FormattedText, FormattedTextList, TextValue}, -}; - -/// Version-independent reference to (front or back) sign text -#[derive(Debug, Default)] -pub struct RawSignText<'a> { - /// Lines of sign text - /// - /// A regular sign always has 4 lines of text. The back of pre-1.20 - /// signs is represented as a [SignText] without any `messages`. - pub messages: Vec<&'a TextValue>, - /// Sign color - /// - /// Defaults to "black". - pub color: Option<&'a str>, -} - -/// The color to use for signs without a color attribute ("black") -const DEFAULT_COLOR: Color = Color([0, 0, 0]); - -/// Map of text colors associated with dyes (except for black) -static DYE_COLORS: phf::Map<&'static str, Color> = phf::phf_map! { - "white" => Color([255, 255, 255]), - "orange" => Color([255, 104, 31]), - "magenta" => Color([255, 0, 255]), - "light_blue" => Color([154, 192, 205]), - "yellow" => Color([255, 255, 0]), - "lime" => Color([191, 255, 0]), - "pink" => Color([255, 105, 180]), - "gray" => Color([128, 128, 128]), - "light_gray" => Color([211, 211, 211]), - "cyan" => Color([0, 255, 255]), - "purple" => Color([160, 32, 240]), - "blue" => Color([0, 0, 255]), - "brown" => Color([139, 69, 19]), - "green" => Color([0, 255, 0]), - "red" => Color([255, 0, 0]), -}; - -impl RawSignText<'_> { - /// Decodes the [RawSignText] into a [SignText] - pub fn decode(&self, data_version: u32) -> SignText { - let color = self - .color - .map(|c| DYE_COLORS.get(c).copied().unwrap_or(DEFAULT_COLOR)); - let parent = FormattedText { - color, - ..Default::default() - }; - SignText( - self.messages - .iter() - .map(|message| message.deserialize(data_version).linearize(&parent)) - .collect(), - ) - } -} - -impl<'a> From<&'a de::BlockEntitySignV1_20Text> for RawSignText<'a> { - fn from(value: &'a de::BlockEntitySignV1_20Text) -> Self { - RawSignText { - messages: value.messages.iter().collect(), - color: value.color.as_deref(), - } - } -} - -/// Helper methods for [de::BlockEntitySign] -pub trait BlockEntitySignExt { - /// Returns the front and back text of a sign in a version-indepentent format - fn text(&self) -> (RawSignText, RawSignText); -} - -impl BlockEntitySignExt for de::BlockEntitySign { - fn text(&self) -> (RawSignText, RawSignText) { - match self { - de::BlockEntitySign::V0 { - text1, - text2, - text3, - text4, - color, - } => ( - RawSignText { - messages: vec![text1, text2, text3, text4], - color: color.as_deref(), - }, - Default::default(), - ), - de::BlockEntitySign::V1_20 { - front_text, - back_text, - } => (front_text.into(), back_text.into()), - } - } -} - -#[derive(Debug, Default, Serialize, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)] -/// Deserialized and linearized sign text -pub struct SignText(pub Vec); - -impl SignText { - /// Checks if all lines of the sign text are empty - pub fn is_empty(&self) -> bool { - self.0.iter().all(|line| line.is_empty()) - } -} - -impl Display for SignText { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let mut iter = self.0.iter(); - - let Some(first) = iter.next() else { - return Ok(()); - }; - first.fmt(f)?; - - for text in iter { - f.write_str("\n")?; - text.fmt(f)?; - } - - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::*; - - fn formatted_text(text: &str) -> FormattedText { - FormattedText { - text: text.to_string(), - ..Default::default() - } - } - - #[test] - fn test_sign_text_display() { - let sign_text = SignText(vec![ - FormattedTextList(vec![formatted_text("a"), formatted_text("b")]), - FormattedTextList(vec![formatted_text("c")]), - FormattedTextList(vec![formatted_text("d")]), - FormattedTextList(vec![formatted_text("e")]), - ]); - assert_eq!("ab\nc\nd\ne", sign_text.to_string()); - } -} diff --git a/src/world/text_value.rs b/src/world/text_value.rs deleted file mode 100644 index 3de6593..0000000 --- a/src/world/text_value.rs +++ /dev/null @@ -1,274 +0,0 @@ -//! Newtype and helper methods for handling Minecraft text values - -use std::{collections::VecDeque, fmt::Display}; - -use bincode::{Decode, Encode}; -use minedmap_resource::Color; -use serde::{Deserialize, Serialize}; - -/// A span of formatted text -/// -/// A [TextValue] consists of a tree of [FormattedText] nodes (canonically -/// represented as a [FormattedTextTree], but other kinds are possible with -/// is handled by [DeserializedText]. -/// -/// Formatting that is not set in a node is inherited from the parent. -#[derive( - Debug, Default, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Encode, Decode, -)] -pub struct FormattedText { - #[serde(default)] - /// Text content - pub text: String, - /// Text color - #[serde(skip_serializing_if = "Option::is_none", with = "text_color")] - pub color: Option, - /// Bold formatting - #[serde(skip_serializing_if = "Option::is_none")] - pub bold: Option, - /// Italic formatting - #[serde(skip_serializing_if = "Option::is_none")] - pub italic: Option, - /// Underlines formatting - #[serde(skip_serializing_if = "Option::is_none")] - pub underlined: Option, - /// Strikethrough formatting - #[serde(skip_serializing_if = "Option::is_none")] - pub strikethrough: Option, - /// Obfuscated formatting - #[serde(skip_serializing_if = "Option::is_none")] - pub obfuscated: Option, -} - -impl FormattedText { - /// Fills in unset formatting fields from a parent node - pub fn inherit(self, parent: &Self) -> Self { - FormattedText { - text: self.text, - color: self.color.or(parent.color), - bold: self.bold.or(parent.bold), - italic: self.italic.or(parent.italic), - underlined: self.underlined.or(parent.underlined), - strikethrough: self.strikethrough.or(parent.strikethrough), - obfuscated: self.obfuscated.or(parent.obfuscated), - } - } -} - -impl Display for FormattedText { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.text.fmt(f) - } -} - -/// A tree of [FormattedText] nodes -/// -/// Each node including the root has a `text` and a list of children (`extra`). -#[derive(Debug, Deserialize, Default)] -pub struct FormattedTextTree { - /// Root node content - #[serde(flatten)] - text: FormattedText, - /// List of child trees - #[serde(default)] - extra: VecDeque, -} - -impl From for FormattedTextTree { - fn from(value: String) -> Self { - FormattedTextTree { - text: FormattedText { - text: value, - ..Default::default() - }, - extra: VecDeque::new(), - } - } -} - -/// List of [FormattedText] -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Encode, Decode)] -pub struct FormattedTextList(pub Vec); - -impl FormattedTextList { - /// Returns `true` when [FormattedTextList] does not contain any text - pub fn is_empty(&self) -> bool { - self.0.iter().all(|text| text.text.is_empty()) - } -} - -impl Display for FormattedTextList { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for text in &self.0 { - text.fmt(f)?; - } - - Ok(()) - } -} - -/// Raw deserialized [TextValue] -/// -/// A [TextValue] can contain various different types serialized as JSON or NBT. -#[derive(Debug, Deserialize)] -#[serde(untagged)] -pub enum DeserializedText { - /// Unformatted string - String(String), - /// Unformatted number (will be converted to a string) - Number(f32), - /// Unformatted boolean (will be converted to a string) - Boolean(bool), - /// List of [DeserializedText] - /// - /// The tail elements are appended as children of the head element. - List(VecDeque), - /// The canonical [FormattedTextTree] structure - Object(FormattedTextTree), -} - -impl DeserializedText { - /// Converts a [DeserializedText] into the regular [FormattedTextTree] format - /// - /// Most variants are simply converted to strings. A list is handled by - /// appending all tail elements to the `extra` field of the head. - pub fn canonicalize(self) -> FormattedTextTree { - match self { - DeserializedText::Object(obj) => obj, - DeserializedText::String(s) => FormattedTextTree::from(s), - DeserializedText::Number(n) => FormattedTextTree::from(n.to_string()), - DeserializedText::Boolean(b) => FormattedTextTree::from(b.to_string()), - DeserializedText::List(mut list) => { - let mut obj = list - .pop_front() - .map(|t| t.canonicalize()) - .unwrap_or_default(); - obj.extra.append(&mut list); - obj - } - } - } - - /// Converts the tree of [FormattedText] nodes into a linear list by - /// copying formatting flags into each node. - pub fn linearize(self, parent: &FormattedText) -> FormattedTextList { - let obj = self.canonicalize(); - let mut ret = vec![obj.text.inherit(parent)]; - - for extra in obj.extra { - ret.append(&mut extra.linearize(&ret[0]).0); - } - - FormattedTextList(ret) - } -} - -impl Default for DeserializedText { - fn default() -> Self { - DeserializedText::Object(FormattedTextTree::from(String::new())) - } -} - -/// Minecraft raw text value -#[derive(Debug, Deserialize)] -pub struct TextValue(pub fastnbt::Value); - -impl TextValue { - /// Deserializes a [TextValue] into a [DeserializedText] - pub fn deserialize(&self, data_version: u32) -> DeserializedText { - // TODO: Improve error handling - // - // Unfortunately, there are a number of weird ways an empty sign coould - // be encoded (for example a compound with an "" key), so for now we - // simply interpret undecodable data as empty. - if data_version < 4290 { - let fastnbt::Value::String(json) = &self.0 else { - return DeserializedText::default(); - }; - - serde_json::from_str(json).unwrap_or_default() - } else { - fastnbt::from_value(&self.0).unwrap_or_default() - } - } -} - -mod text_color { - //! Helpers for serializing and deserializing [FormattedText](super::FormattedText) colors - - use minedmap_resource::Color; - use serde::{ - Deserializer, Serializer, - de::{self, Visitor}, - ser::Error as _, - }; - - /// Named text colors - static COLORS: phf::Map<&'static str, Color> = phf::phf_map! { - "black" => Color([0x00, 0x00, 0x00]), - "dark_blue" => Color([0x00, 0x00, 0xAA]), - "dark_green" => Color([0x00, 0xAA, 0x00]), - "dark_aqua" => Color([0x00, 0xAA, 0xAA]), - "dark_red" => Color([0xAA, 0x00, 0x00]), - "dark_purple" => Color([0xAA, 0x00, 0xAA]), - "gold" => Color([0xFF, 0xAA, 0x00]), - "gray" => Color([0xAA, 0xAA, 0xAA]), - "dark_gray" => Color([0x55, 0x55, 0x55]), - "blue" => Color([0x55, 0x55, 0xFF]), - "green" => Color([0x55, 0xFF, 0x55]), - "aqua" => Color([0x55, 0xFF, 0xFF]), - "red" => Color([0xFF, 0x55, 0x55]), - "light_purple" => Color([0xFF, 0x55, 0xFF]), - "yellow" => Color([0xFF, 0xFF, 0x55]), - "white" => Color([0xFF, 0xFF, 0xFF]), - }; - - /// serde serialize function for [FormattedText::color](super::FormattedText::color) - pub fn serialize(color: &Option, serializer: S) -> Result - where - S: Serializer, - { - let &Some(color) = color else { - return Err(S::Error::custom("serialize called for None sign color")); - }; - - let text = format!("#{:02x}{:02x}{:02x}", color.0[0], color.0[1], color.0[2]); - serializer.serialize_str(&text) - } - - /// serde [Visitor] for use by [deserialize] - struct ColorVisitor; - - impl Visitor<'_> for ColorVisitor { - type Value = Option; - - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("a string representing a color") - } - - fn visit_str(self, color: &str) -> Result - where - E: de::Error, - { - if let Some(hex) = color.strip_prefix("#") { - if let Ok(value) = u32::from_str_radix(hex, 16) { - return Ok(Some(Color([ - (value >> 16) as u8, - (value >> 8) as u8, - value as u8, - ]))); - } - } - - Ok(COLORS.get(color).copied()) - } - } - - /// serde deserialize function for [FormattedText::color](super::FormattedText::color) - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - deserializer.deserialize_str(ColorVisitor) - } -} diff --git a/viewer/.dockerignore b/viewer/.dockerignore deleted file mode 100644 index 3af0ccb..0000000 --- a/viewer/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -/data diff --git a/viewer/Dockerfile b/viewer/Dockerfile deleted file mode 100644 index 524fd4c..0000000 --- a/viewer/Dockerfile +++ /dev/null @@ -1,3 +0,0 @@ -FROM docker.io/library/nginx:alpine-slim -COPY . /usr/share/nginx/html -# datadir should be mounted to: /usr/share/nginx/html/data diff --git a/viewer/MinedMap.js b/viewer/MinedMap.js index 61188b1..f6f444e 100644 --- a/viewer/MinedMap.js +++ b/viewer/MinedMap.js @@ -1,124 +1,106 @@ -// bsearch-based array element check -function contains(array, elem) { - let min = 0, max = array.length; - - while (min < max) { - const i = min + Math.floor((max-min)/2); - const cur = array[i]; - - if (cur === elem) - return true; - else if (cur < elem) - min = i + 1; - else - max = i; - } - - return false; -} - -const signKinds = { - sign: { - iconSize: [26, 28], - popupAnchor: [0, -20], - }, - wall_sign: { - iconSize: [26, 18], - popupAnchor: [0, -15], - }, - hanging_sign: { - iconSize: [28, 24], - popupAnchor: [0, -18], - }, - hanging_wall_sign: { - iconSize: [28, 28], - popupAnchor: [0, -20], - }, -} - -const params = {}; -const signIcons = {}; -const markers = {}; - -let updateHash = () => {}; - -function coordKey(coords) { - if (!coords) - return null; - - return `${coords[0]},${coords[1]}`; -} - -function getMarker(coords) { - return markers[coordKey(coords)]; -} - -function signIcon(material, kind) { - function createSignIcon(material, kind) { - const {iconSize, popupAnchor} = signKinds[kind]; - - return L.icon({ - iconUrl: `images/icon/${material}_${kind}.png`, - iconSize, - popupAnchor, - shadowUrl: `images/icon/shadow_${kind}.png`, - shadowSize: [iconSize[0]+8, iconSize[1]+8], - className: 'overzoomed', - }); - } - - - let icons = signIcons[material] ??= {}; - return icons[kind] ??= createSignIcon(material, kind); -} - -const MinedMapLayer = L.TileLayer.extend({ - initialize: function (mipmaps, layer, tile_extension) { - L.TileLayer.prototype.initialize.call(this, '', { - detectRetina: true, - tileSize: 512, - zoomReverse: true, - minZoom: -(mipmaps.length-1), - maxZoom: 0, - attribution: 'Generated by MinedMap', - }); - - this.options.maxNativeZoom = this.options.maxZoom; - this.options.maxZoom = undefined; - +var MinedMapLayer = L.GridLayer.extend({ + initialize: function (mipmaps, layer) { this.mipmaps = mipmaps; this.layer = layer; - this.ext = tile_extension; + + this.zoomOffset = L.Browser.retina ? 1 : 0; + + this.options.tileSize = L.Browser.retina ? 256 : 512; + this.options.attribution = 'Generated by MinedMap'; + + this.options.minZoom = -(mipmaps.length-1 + this.zoomOffset); + this.options.maxNativeZoom = -this.zoomOffset; + + // for https://github.com/Leaflet/Leaflet/issues/137 + if (!L.Browser.android) { + this.on('tileunload', this._onTileRemove); + } }, createTile: function (coords, done) { - const tile = L.TileLayer.prototype.createTile.call(this, coords, done); + var tile = document.createElement('img'); - if (coords.z - this.options.zoomOffset >= 0) + tile.onload = L.bind(this._tileOnLoad, this, done, tile); + tile.onerror = L.bind(this._tileOnError, this, done, tile); + + /* + Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons + http://www.w3.org/TR/WCAG20-TECHS/H67 + */ + tile.alt = ''; + + /* + Set role="presentation" to force screen readers to ignore this + https://www.w3.org/TR/wai-aria/roles#textalternativecomputation + */ + tile.setAttribute('role', 'presentation'); + + var z = -(coords.z + this.zoomOffset); + if (z < 0) + z = 0; + + var mipmap = this.mipmaps[z]; + + if (coords.x >= mipmap.info.minX && coords.x <= mipmap.info.maxX && + coords.y >= mipmap.info.minZ && coords.y <= mipmap.info.maxZ && + mipmap.regions[coords.y-mipmap.info.minZ][coords.x-mipmap.info.minX]) + tile.src = 'data/'+this.layer+'/'+z+'/r.'+coords.x+'.'+coords.y+'.png'; + + if (z === 0) L.DomUtil.addClass(tile, 'overzoomed'); return tile; }, - getTileUrl: function (coords) { - let z = -coords.z + this.options.zoomOffset; - if (z < 0) - z = 0; + _tileOnLoad: function (done, tile) { + if (L.Browser.ielt9) + setTimeout(Util.bind(done, this, null, tile), 0); + else + done(null, tile); + }, - const mipmap = this.mipmaps[z]; + _tileOnError: function (done, tile, e) { + done(e, tile); + }, - if (coords.x < mipmap.bounds.minX || coords.x > mipmap.bounds.maxX || - coords.y < mipmap.bounds.minZ || coords.y > mipmap.bounds.maxZ || - !contains(mipmap.regions[coords.y] || [], coords.x)) - return L.Util.emptyImageUrl; + _onTileRemove: function (e) { + e.tile.onload = null; + }, + _abortLoading: function () { + var i, tile; + for (i in this._tiles) { + if (this._tiles[i].coords.z !== this._tileZoom) { + tile = this._tiles[i].el; - return `data/${this.layer}/${z}/r.${coords.x}.${coords.y}.${this.ext}`; + tile.onload = L.Util.falseFn; + tile.onerror = L.Util.falseFn; + + if (!tile.complete) { + tile.src = L.Util.emptyImageUrl; + L.DomUtil.remove(tile); + } + } + } + }, + + _removeTile: function (key) { + var tile = this._tiles[key]; + if (!tile) { return; } + + // Cancels any pending http requests associated with the tile + // unless we're on Android's stock browser, + // see https://github.com/Leaflet/Leaflet/issues/137 + if (!L.Browser.androidStock) { + tile.el.setAttribute('src', L.Util.emptyImageUrl); + } + + return L.GridLayer.prototype._removeTile.call(this, key); }, }); -const CoordControl = L.Control.extend({ +var CoordControl = L.Control.extend({ initialize: function () { this.options.position = 'bottomleft'; }, @@ -137,15 +119,15 @@ const CoordControl = L.Control.extend({ }); -const parseHash = function () { - const args = {}; +var parseHash = function () { + var args = {}; if (window.location.hash) { - const parts = window.location.hash.substring(1).split('&'); + var parts = window.location.hash.substr(1).split('&'); - for (const part of parts) { - const key_value = part.split('='); - const key = key_value[0], value = key_value.slice(1).join('='); + for (var i = 0; i < parts.length; i++) { + var key_value = parts[i].split('='); + var key = key_value[0], value = key_value.slice(1).join('='); args[key] = value; } @@ -154,282 +136,88 @@ const parseHash = function () { return args; } -function formatSignLine(line) { - const el = document.createElement('span'); - el.style.whiteSpace = 'pre'; - - for (const span of line) { - const child = document.createElement('span'); - child.textContent = span.text; - - let color = span.color ?? ''; - if (color[0] !== '#') - color = '#000000'; - - if (span.bold) - child.style.fontWeight = 'bold'; - if (span.italic) - child.style.fontStyle = 'italic'; - - child.style.textDecoration = ''; - if (span.underlined) - child.style.textDecoration += ' underline'; - if (span.strikethrough) - child.style.textDecoration += ' line-through'; - - child.style.color = color; - if (span.obfuscated) { - child.style.backgroundColor = color; - child.className = 'obfuscated'; - } - - el.appendChild(child); - } - return el; -} - -function createSign(sign, back) { - // standing signs - function px(base) { - const scale = 11; - return (base*scale)+'px'; - } - // hanging signs - function pxh(base) { - const scale = 16; - return (base*scale)+'px'; - } - - const sizes = { - sign: { - width: px(24), - height: px(12), - paddingTop: px(0), - paddingBottom: px(14), - }, - wall_sign: { - width: px(24), - height: px(12), - paddingTop: px(0), - paddingBottom: px(0), - }, - hanging_sign: { - width: pxh(16), - height: pxh(10), - paddingTop: pxh(4), - paddingBottom: pxh(0), - }, - hanging_wall_sign: { - width: pxh(16), - height: pxh(10), - paddingTop: pxh(6), - paddingBottom: pxh(0), - }, - }; - const size = sizes[sign.kind]; - - const wrapper = document.createElement('div'); - wrapper.classList = 'sign-wrapper'; - - const title = document.createElement('div'); - title.classList = 'sign-title' - title.textContent = `Sign at ${sign.x}/${sign.y}/${sign.z}`; - if (back) - title.textContent += ' (back)'; - title.textContent += ':'; - - wrapper.appendChild(title); - - const container = document.createElement('div'); - container.style.width = size.width; - container.style.height = size.height; - container.style.paddingTop = size.paddingTop; - container.style.paddingBottom = size.paddingBottom; - container.style.backgroundImage = `url(images/bg/${sign.material}_${sign.kind}.png)`; - container.classList = 'sign-container overzoomed'; - - const content = document.createElement('div'); - content.classList = 'sign-content'; - - let text = []; - if (!back && sign.front_text) - text = sign.front_text; - else if (back && sign.back_text) - text = sign.back_text; - - for (const line of text) { - content.appendChild(formatSignLine(line)); - content.appendChild(document.createElement('br')); - } - - container.appendChild(content); - wrapper.appendChild(container); - - return wrapper; -} - -async function loadSigns(signLayer) { - const response = await fetch('data/entities.json', {cache: 'no-store'}); - const res = await response.json(); - - const groups = {}; - - // Group signs by x,z coordinates - for (const sign of res.signs) { - const key = coordKey([sign.x, sign.z]); - const group = groups[key] ??= []; - group.push(sign); - } - - for (const [key, group] of Object.entries(groups)) { - const el = document.createElement('div'); - - let material; - let kind; - - // Sort from top to bottom - group.sort((a, b) => b.y - a.y); - - for (const sign of group) { - el.appendChild(createSign(sign, false)); - - if (sign.back_text) - el.appendChild(createSign(sign, true)); - - material ??= sign.material; - kind ??= sign.kind; - } - - // Default material - material ??= 'oak'; - - const [x, z] = key.split(',').map((i) => +i); - - const popup = L.popup().setContent(el); - - popup.on('add', () => { - params.marker = [x, z]; - updateHash(); - }); - popup.on('remove', () => { - params.marker = null; - updateHash(); - }); - - const marker = L.marker([-z-0.5, x+0.5], { - icon: signIcon(material, kind), - }).addTo(signLayer).bindPopup(popup); - - markers[coordKey([x, z])] = marker; - - if (params.marker && x === params.marker[0] && z === params.marker[1]) - marker.openPopup(); - } -} window.createMap = function () { - (async function () { - const response = await fetch('data/info.json', {cache: 'no-store'}); - const res = await response.json(); - const {mipmaps, spawn} = res; - const features = res.features || {}; - const tile_extension = res.tile_extension || 'png'; + var xhr = new XMLHttpRequest(); + xhr.onload = function () { + var res = JSON.parse(this.responseText), + mipmaps = res.mipmaps, + spawn = res.spawn; - const updateParams = function () { - const args = parseHash(); + var x, z, zoom, light; - params.zoom = parseInt(args['zoom']); - params.x = parseFloat(args['x']); - params.z = parseFloat(args['z']); - params.light = parseInt(args['light']); - params.signs = parseInt(args['signs'] ?? '1'); - params.marker = (args['marker'] ?? '').split(',').map((i) => +i); + var updateParams = function () { + var args = parseHash(); - if (isNaN(params.zoom)) - params.zoom = 0; - if (isNaN(params.x)) - params.x = spawn.x; - if (isNaN(params.z)) - params.z = spawn.z; - if (!features.signs || isNaN(params.marker[0]) || isNaN(params.marker[1])) - params.marker = null; + zoom = parseInt(args['zoom']); + x = parseFloat(args['x']); + z = parseFloat(args['z']); + light = parseInt(args['light']); + + if (isNaN(zoom)) + zoom = 0; + if (isNaN(x)) + x = spawn.x; + if (isNaN(z)) + z = spawn.z; }; updateParams(); - const map = L.map('map', { - center: [-params.z, params.x], - zoom: params.zoom, + var map = L.map('map', { + center: [-z, x], + zoom: zoom, minZoom: -(mipmaps.length-1), - maxZoom: 5, + maxZoom: 3, crs: L.CRS.Simple, maxBounds: [ - [-512*(mipmaps[0].bounds.maxZ+1), 512*mipmaps[0].bounds.minX], - [-512*mipmaps[0].bounds.minZ, 512*(mipmaps[0].bounds.maxX+1)], + [-512*(mipmaps[0].info.maxZ+1), 512*mipmaps[0].info.minX], + [-512*mipmaps[0].info.minZ, 512*(mipmaps[0].info.maxX+1)], ], }); - const overlayMaps = {}; + var mapLayer = new MinedMapLayer(mipmaps, 'map'); + var lightLayer = new MinedMapLayer(mipmaps, 'light'); - const mapLayer = new MinedMapLayer(mipmaps, 'map', tile_extension); mapLayer.addTo(map); - const lightLayer = new MinedMapLayer(mipmaps, 'light', tile_extension); - overlayMaps['Illumination'] = lightLayer; - if (params.light) + if (light) map.addLayer(lightLayer); - let signLayer; - if (features.signs) { - signLayer = L.layerGroup(); - loadSigns(signLayer); - if (params.signs) - map.addLayer(signLayer); - - overlayMaps['Signs'] = signLayer; - } + var overlayMaps = { + "Illumination": lightLayer, + }; L.control.layers({}, overlayMaps).addTo(map); - const coordControl = new CoordControl(); + var coordControl = new CoordControl(); coordControl.addTo(map); map.on('mousemove', function(e) { coordControl.update(Math.round(e.latlng.lng), Math.round(-e.latlng.lat)); }); - const makeHash = function () { - let ret = '#x='+params.x+'&z='+params.z; + var makeHash = function () { + var ret = '#x='+x+'&z='+z; - if (params.zoom != 0) - ret += '&zoom='+params.zoom; + if (zoom != 0) + ret += '&zoom='+zoom; if (map.hasLayer(lightLayer)) ret += '&light=1'; - if (features.signs && !map.hasLayer(signLayer)) - ret += '&signs=0'; - if (params.marker) { - ret += `&marker=${params.marker[0]},${params.marker[1]}`; - } return ret; }; - updateHash = function () { + var updateHash = function () { window.location.hash = makeHash(); }; - const refreshHash = function (ev) { - if (ev.type === 'layeradd' || ev.type === 'layerremove') { - if (ev.layer !== lightLayer && ev.layer !== signLayer) - return; - } - - const center = map.getCenter(); - - params.zoom = map.getZoom(); - params.x = Math.round(center.lng); - params.z = Math.round(-center.lat); + var refreshHash = function () { + zoom = map.getZoom(); + center = map.getCenter(); + x = Math.round(center.lng); + z = Math.round(-center.lat); updateHash(); } @@ -445,29 +233,20 @@ window.createMap = function () { if (window.location.hash === makeHash()) return; - const prevMarkerCoords = params.marker; - updateParams(); - if (params.light) + map.setView([-z, x], zoom); + + if (light) map.addLayer(lightLayer); else map.removeLayer(lightLayer); - if (features.signs) { - if (params.signs) - map.addLayer(signLayer); - else - map.removeLayer(signLayer); - - if (coordKey(prevMarkerCoords) !== coordKey(params.marker)) - getMarker(params.marker)?.openPopup(); - } - - map.setView([-params.z, params.x], params.zoom); - updateHash(); }; - })(); + }; + + xhr.open('GET', 'data/info.json', true); + xhr.send(); } diff --git a/viewer/images/README.md b/viewer/images/README.md deleted file mode 100644 index 2e840f1..0000000 --- a/viewer/images/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# README - -The images in this directory are assets directly taken from Minecraft, or are derived from Minecraft -assets. They are copyrighted by Mojang/Microsoft, and are used in accordance with the -[Minecraft Usage Guidelines](https://www.minecraft.net/en-us/usage-guidelines). - - diff --git a/viewer/images/bg/acacia_hanging_sign.png b/viewer/images/bg/acacia_hanging_sign.png deleted file mode 100644 index 33e3191..0000000 Binary files a/viewer/images/bg/acacia_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/acacia_hanging_wall_sign.png b/viewer/images/bg/acacia_hanging_wall_sign.png deleted file mode 100644 index c975fc3..0000000 Binary files a/viewer/images/bg/acacia_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/acacia_sign.png b/viewer/images/bg/acacia_sign.png deleted file mode 100644 index ccc6e47..0000000 Binary files a/viewer/images/bg/acacia_sign.png and /dev/null differ diff --git a/viewer/images/bg/acacia_wall_sign.png b/viewer/images/bg/acacia_wall_sign.png deleted file mode 100644 index f7ec621..0000000 Binary files a/viewer/images/bg/acacia_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/bamboo_hanging_sign.png b/viewer/images/bg/bamboo_hanging_sign.png deleted file mode 100644 index 5a66129..0000000 Binary files a/viewer/images/bg/bamboo_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/bamboo_hanging_wall_sign.png b/viewer/images/bg/bamboo_hanging_wall_sign.png deleted file mode 100644 index 325e4f0..0000000 Binary files a/viewer/images/bg/bamboo_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/bamboo_sign.png b/viewer/images/bg/bamboo_sign.png deleted file mode 100644 index dc19aef..0000000 Binary files a/viewer/images/bg/bamboo_sign.png and /dev/null differ diff --git a/viewer/images/bg/bamboo_wall_sign.png b/viewer/images/bg/bamboo_wall_sign.png deleted file mode 100644 index 8182862..0000000 Binary files a/viewer/images/bg/bamboo_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/birch_hanging_sign.png b/viewer/images/bg/birch_hanging_sign.png deleted file mode 100644 index 4b4972c..0000000 Binary files a/viewer/images/bg/birch_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/birch_hanging_wall_sign.png b/viewer/images/bg/birch_hanging_wall_sign.png deleted file mode 100644 index b744d54..0000000 Binary files a/viewer/images/bg/birch_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/birch_sign.png b/viewer/images/bg/birch_sign.png deleted file mode 100644 index 0d76b7a..0000000 Binary files a/viewer/images/bg/birch_sign.png and /dev/null differ diff --git a/viewer/images/bg/birch_wall_sign.png b/viewer/images/bg/birch_wall_sign.png deleted file mode 100644 index c83d292..0000000 Binary files a/viewer/images/bg/birch_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/cherry_hanging_sign.png b/viewer/images/bg/cherry_hanging_sign.png deleted file mode 100644 index 2d6cf71..0000000 Binary files a/viewer/images/bg/cherry_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/cherry_hanging_wall_sign.png b/viewer/images/bg/cherry_hanging_wall_sign.png deleted file mode 100644 index a7325f3..0000000 Binary files a/viewer/images/bg/cherry_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/cherry_sign.png b/viewer/images/bg/cherry_sign.png deleted file mode 100644 index 91b1949..0000000 Binary files a/viewer/images/bg/cherry_sign.png and /dev/null differ diff --git a/viewer/images/bg/cherry_wall_sign.png b/viewer/images/bg/cherry_wall_sign.png deleted file mode 100644 index 48d9511..0000000 Binary files a/viewer/images/bg/cherry_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/crimson_hanging_sign.png b/viewer/images/bg/crimson_hanging_sign.png deleted file mode 100644 index aa3dabe..0000000 Binary files a/viewer/images/bg/crimson_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/crimson_hanging_wall_sign.png b/viewer/images/bg/crimson_hanging_wall_sign.png deleted file mode 100644 index 35a7892..0000000 Binary files a/viewer/images/bg/crimson_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/crimson_sign.png b/viewer/images/bg/crimson_sign.png deleted file mode 100644 index 08e2322..0000000 Binary files a/viewer/images/bg/crimson_sign.png and /dev/null differ diff --git a/viewer/images/bg/crimson_wall_sign.png b/viewer/images/bg/crimson_wall_sign.png deleted file mode 100644 index ce47274..0000000 Binary files a/viewer/images/bg/crimson_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/dark_oak_hanging_sign.png b/viewer/images/bg/dark_oak_hanging_sign.png deleted file mode 100644 index 7155078..0000000 Binary files a/viewer/images/bg/dark_oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/dark_oak_hanging_wall_sign.png b/viewer/images/bg/dark_oak_hanging_wall_sign.png deleted file mode 100644 index 73479e8..0000000 Binary files a/viewer/images/bg/dark_oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/dark_oak_sign.png b/viewer/images/bg/dark_oak_sign.png deleted file mode 100644 index 8b1307d..0000000 Binary files a/viewer/images/bg/dark_oak_sign.png and /dev/null differ diff --git a/viewer/images/bg/dark_oak_wall_sign.png b/viewer/images/bg/dark_oak_wall_sign.png deleted file mode 100644 index a163f04..0000000 Binary files a/viewer/images/bg/dark_oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/jungle_hanging_sign.png b/viewer/images/bg/jungle_hanging_sign.png deleted file mode 100644 index ecf1e87..0000000 Binary files a/viewer/images/bg/jungle_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/jungle_hanging_wall_sign.png b/viewer/images/bg/jungle_hanging_wall_sign.png deleted file mode 100644 index 5cf2b40..0000000 Binary files a/viewer/images/bg/jungle_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/jungle_sign.png b/viewer/images/bg/jungle_sign.png deleted file mode 100644 index eb7d54d..0000000 Binary files a/viewer/images/bg/jungle_sign.png and /dev/null differ diff --git a/viewer/images/bg/jungle_wall_sign.png b/viewer/images/bg/jungle_wall_sign.png deleted file mode 100644 index 6eb610b..0000000 Binary files a/viewer/images/bg/jungle_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/mangrove_hanging_sign.png b/viewer/images/bg/mangrove_hanging_sign.png deleted file mode 100644 index 7e36396..0000000 Binary files a/viewer/images/bg/mangrove_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/mangrove_hanging_wall_sign.png b/viewer/images/bg/mangrove_hanging_wall_sign.png deleted file mode 100644 index 4fd9948..0000000 Binary files a/viewer/images/bg/mangrove_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/mangrove_sign.png b/viewer/images/bg/mangrove_sign.png deleted file mode 100644 index d03bfd0..0000000 Binary files a/viewer/images/bg/mangrove_sign.png and /dev/null differ diff --git a/viewer/images/bg/mangrove_wall_sign.png b/viewer/images/bg/mangrove_wall_sign.png deleted file mode 100644 index 8fe527a..0000000 Binary files a/viewer/images/bg/mangrove_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/oak_hanging_sign.png b/viewer/images/bg/oak_hanging_sign.png deleted file mode 100644 index fea3a3f..0000000 Binary files a/viewer/images/bg/oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/oak_hanging_wall_sign.png b/viewer/images/bg/oak_hanging_wall_sign.png deleted file mode 100644 index 9212d07..0000000 Binary files a/viewer/images/bg/oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/oak_sign.png b/viewer/images/bg/oak_sign.png deleted file mode 100644 index fca0a80..0000000 Binary files a/viewer/images/bg/oak_sign.png and /dev/null differ diff --git a/viewer/images/bg/oak_wall_sign.png b/viewer/images/bg/oak_wall_sign.png deleted file mode 100644 index b6f9879..0000000 Binary files a/viewer/images/bg/oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/pale_oak_hanging_sign.png b/viewer/images/bg/pale_oak_hanging_sign.png deleted file mode 100644 index 972a119..0000000 Binary files a/viewer/images/bg/pale_oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/pale_oak_hanging_wall_sign.png b/viewer/images/bg/pale_oak_hanging_wall_sign.png deleted file mode 100644 index cf98cb2..0000000 Binary files a/viewer/images/bg/pale_oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/pale_oak_sign.png b/viewer/images/bg/pale_oak_sign.png deleted file mode 100644 index 5ea5a7e..0000000 Binary files a/viewer/images/bg/pale_oak_sign.png and /dev/null differ diff --git a/viewer/images/bg/pale_oak_wall_sign.png b/viewer/images/bg/pale_oak_wall_sign.png deleted file mode 100644 index f52f32a..0000000 Binary files a/viewer/images/bg/pale_oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/spruce_hanging_sign.png b/viewer/images/bg/spruce_hanging_sign.png deleted file mode 100644 index 295a2de..0000000 Binary files a/viewer/images/bg/spruce_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/spruce_hanging_wall_sign.png b/viewer/images/bg/spruce_hanging_wall_sign.png deleted file mode 100644 index 87a62f9..0000000 Binary files a/viewer/images/bg/spruce_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/spruce_sign.png b/viewer/images/bg/spruce_sign.png deleted file mode 100644 index cc5cbab..0000000 Binary files a/viewer/images/bg/spruce_sign.png and /dev/null differ diff --git a/viewer/images/bg/spruce_wall_sign.png b/viewer/images/bg/spruce_wall_sign.png deleted file mode 100644 index f8730b9..0000000 Binary files a/viewer/images/bg/spruce_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/warped_hanging_sign.png b/viewer/images/bg/warped_hanging_sign.png deleted file mode 100644 index 100e0fc..0000000 Binary files a/viewer/images/bg/warped_hanging_sign.png and /dev/null differ diff --git a/viewer/images/bg/warped_hanging_wall_sign.png b/viewer/images/bg/warped_hanging_wall_sign.png deleted file mode 100644 index a80b913..0000000 Binary files a/viewer/images/bg/warped_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/bg/warped_sign.png b/viewer/images/bg/warped_sign.png deleted file mode 100644 index 8fdc181..0000000 Binary files a/viewer/images/bg/warped_sign.png and /dev/null differ diff --git a/viewer/images/bg/warped_wall_sign.png b/viewer/images/bg/warped_wall_sign.png deleted file mode 100644 index 86a7cab..0000000 Binary files a/viewer/images/bg/warped_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/acacia_hanging_sign.png b/viewer/images/icon/acacia_hanging_sign.png deleted file mode 100644 index 79c8ee5..0000000 Binary files a/viewer/images/icon/acacia_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/acacia_hanging_wall_sign.png b/viewer/images/icon/acacia_hanging_wall_sign.png deleted file mode 100644 index b8872cb..0000000 Binary files a/viewer/images/icon/acacia_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/acacia_sign.png b/viewer/images/icon/acacia_sign.png deleted file mode 100644 index c698b7d..0000000 Binary files a/viewer/images/icon/acacia_sign.png and /dev/null differ diff --git a/viewer/images/icon/acacia_wall_sign.png b/viewer/images/icon/acacia_wall_sign.png deleted file mode 100644 index 83de3ac..0000000 Binary files a/viewer/images/icon/acacia_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/bamboo_hanging_sign.png b/viewer/images/icon/bamboo_hanging_sign.png deleted file mode 100644 index 8acef55..0000000 Binary files a/viewer/images/icon/bamboo_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/bamboo_hanging_wall_sign.png b/viewer/images/icon/bamboo_hanging_wall_sign.png deleted file mode 100644 index a23377e..0000000 Binary files a/viewer/images/icon/bamboo_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/bamboo_sign.png b/viewer/images/icon/bamboo_sign.png deleted file mode 100644 index d8702d1..0000000 Binary files a/viewer/images/icon/bamboo_sign.png and /dev/null differ diff --git a/viewer/images/icon/bamboo_wall_sign.png b/viewer/images/icon/bamboo_wall_sign.png deleted file mode 100644 index 9af0ac2..0000000 Binary files a/viewer/images/icon/bamboo_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/birch_hanging_sign.png b/viewer/images/icon/birch_hanging_sign.png deleted file mode 100644 index 79adc54..0000000 Binary files a/viewer/images/icon/birch_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/birch_hanging_wall_sign.png b/viewer/images/icon/birch_hanging_wall_sign.png deleted file mode 100644 index 85f9c2e..0000000 Binary files a/viewer/images/icon/birch_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/birch_sign.png b/viewer/images/icon/birch_sign.png deleted file mode 100644 index f05a4b4..0000000 Binary files a/viewer/images/icon/birch_sign.png and /dev/null differ diff --git a/viewer/images/icon/birch_wall_sign.png b/viewer/images/icon/birch_wall_sign.png deleted file mode 100644 index b82e681..0000000 Binary files a/viewer/images/icon/birch_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/cherry_hanging_sign.png b/viewer/images/icon/cherry_hanging_sign.png deleted file mode 100644 index 2ea0a3f..0000000 Binary files a/viewer/images/icon/cherry_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/cherry_hanging_wall_sign.png b/viewer/images/icon/cherry_hanging_wall_sign.png deleted file mode 100644 index d14b399..0000000 Binary files a/viewer/images/icon/cherry_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/cherry_sign.png b/viewer/images/icon/cherry_sign.png deleted file mode 100644 index d9c7f49..0000000 Binary files a/viewer/images/icon/cherry_sign.png and /dev/null differ diff --git a/viewer/images/icon/cherry_wall_sign.png b/viewer/images/icon/cherry_wall_sign.png deleted file mode 100644 index 8ca0429..0000000 Binary files a/viewer/images/icon/cherry_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/crimson_hanging_sign.png b/viewer/images/icon/crimson_hanging_sign.png deleted file mode 100644 index 629b277..0000000 Binary files a/viewer/images/icon/crimson_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/crimson_hanging_wall_sign.png b/viewer/images/icon/crimson_hanging_wall_sign.png deleted file mode 100644 index 9df4aa2..0000000 Binary files a/viewer/images/icon/crimson_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/crimson_sign.png b/viewer/images/icon/crimson_sign.png deleted file mode 100644 index 7cf1ae7..0000000 Binary files a/viewer/images/icon/crimson_sign.png and /dev/null differ diff --git a/viewer/images/icon/crimson_wall_sign.png b/viewer/images/icon/crimson_wall_sign.png deleted file mode 100644 index 5fc699c..0000000 Binary files a/viewer/images/icon/crimson_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/dark_oak_hanging_sign.png b/viewer/images/icon/dark_oak_hanging_sign.png deleted file mode 100644 index a64df06..0000000 Binary files a/viewer/images/icon/dark_oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/dark_oak_hanging_wall_sign.png b/viewer/images/icon/dark_oak_hanging_wall_sign.png deleted file mode 100644 index 5ec5d94..0000000 Binary files a/viewer/images/icon/dark_oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/dark_oak_sign.png b/viewer/images/icon/dark_oak_sign.png deleted file mode 100644 index 569b97d..0000000 Binary files a/viewer/images/icon/dark_oak_sign.png and /dev/null differ diff --git a/viewer/images/icon/dark_oak_wall_sign.png b/viewer/images/icon/dark_oak_wall_sign.png deleted file mode 100644 index e9bdeb3..0000000 Binary files a/viewer/images/icon/dark_oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/jungle_hanging_sign.png b/viewer/images/icon/jungle_hanging_sign.png deleted file mode 100644 index ec89fff..0000000 Binary files a/viewer/images/icon/jungle_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/jungle_hanging_wall_sign.png b/viewer/images/icon/jungle_hanging_wall_sign.png deleted file mode 100644 index fba8629..0000000 Binary files a/viewer/images/icon/jungle_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/jungle_sign.png b/viewer/images/icon/jungle_sign.png deleted file mode 100644 index 4853e08..0000000 Binary files a/viewer/images/icon/jungle_sign.png and /dev/null differ diff --git a/viewer/images/icon/jungle_wall_sign.png b/viewer/images/icon/jungle_wall_sign.png deleted file mode 100644 index c3d72d2..0000000 Binary files a/viewer/images/icon/jungle_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/mangrove_hanging_sign.png b/viewer/images/icon/mangrove_hanging_sign.png deleted file mode 100644 index f53bf22..0000000 Binary files a/viewer/images/icon/mangrove_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/mangrove_hanging_wall_sign.png b/viewer/images/icon/mangrove_hanging_wall_sign.png deleted file mode 100644 index 79a010a..0000000 Binary files a/viewer/images/icon/mangrove_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/mangrove_sign.png b/viewer/images/icon/mangrove_sign.png deleted file mode 100644 index 467c922..0000000 Binary files a/viewer/images/icon/mangrove_sign.png and /dev/null differ diff --git a/viewer/images/icon/mangrove_wall_sign.png b/viewer/images/icon/mangrove_wall_sign.png deleted file mode 100644 index b1cadce..0000000 Binary files a/viewer/images/icon/mangrove_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/oak_hanging_sign.png b/viewer/images/icon/oak_hanging_sign.png deleted file mode 100644 index 060c4e2..0000000 Binary files a/viewer/images/icon/oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/oak_hanging_wall_sign.png b/viewer/images/icon/oak_hanging_wall_sign.png deleted file mode 100644 index 2bb9dff..0000000 Binary files a/viewer/images/icon/oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/oak_sign.png b/viewer/images/icon/oak_sign.png deleted file mode 100644 index 41b46a5..0000000 Binary files a/viewer/images/icon/oak_sign.png and /dev/null differ diff --git a/viewer/images/icon/oak_wall_sign.png b/viewer/images/icon/oak_wall_sign.png deleted file mode 100644 index bfb9ff7..0000000 Binary files a/viewer/images/icon/oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/pale_oak_hanging_sign.png b/viewer/images/icon/pale_oak_hanging_sign.png deleted file mode 100644 index cd61dd1..0000000 Binary files a/viewer/images/icon/pale_oak_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/pale_oak_hanging_wall_sign.png b/viewer/images/icon/pale_oak_hanging_wall_sign.png deleted file mode 100644 index fefd31a..0000000 Binary files a/viewer/images/icon/pale_oak_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/pale_oak_sign.png b/viewer/images/icon/pale_oak_sign.png deleted file mode 100644 index 3684f5d..0000000 Binary files a/viewer/images/icon/pale_oak_sign.png and /dev/null differ diff --git a/viewer/images/icon/pale_oak_wall_sign.png b/viewer/images/icon/pale_oak_wall_sign.png deleted file mode 100644 index 32257e3..0000000 Binary files a/viewer/images/icon/pale_oak_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/shadow_hanging_sign.png b/viewer/images/icon/shadow_hanging_sign.png deleted file mode 100644 index dbd19a6..0000000 Binary files a/viewer/images/icon/shadow_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/shadow_hanging_wall_sign.png b/viewer/images/icon/shadow_hanging_wall_sign.png deleted file mode 100644 index 771cef5..0000000 Binary files a/viewer/images/icon/shadow_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/shadow_sign.png b/viewer/images/icon/shadow_sign.png deleted file mode 100644 index 9bf1cde..0000000 Binary files a/viewer/images/icon/shadow_sign.png and /dev/null differ diff --git a/viewer/images/icon/shadow_wall_sign.png b/viewer/images/icon/shadow_wall_sign.png deleted file mode 100644 index fe46765..0000000 Binary files a/viewer/images/icon/shadow_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/spruce_hanging_sign.png b/viewer/images/icon/spruce_hanging_sign.png deleted file mode 100644 index bf3c6d0..0000000 Binary files a/viewer/images/icon/spruce_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/spruce_hanging_wall_sign.png b/viewer/images/icon/spruce_hanging_wall_sign.png deleted file mode 100644 index c1c872b..0000000 Binary files a/viewer/images/icon/spruce_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/spruce_sign.png b/viewer/images/icon/spruce_sign.png deleted file mode 100644 index faff405..0000000 Binary files a/viewer/images/icon/spruce_sign.png and /dev/null differ diff --git a/viewer/images/icon/spruce_wall_sign.png b/viewer/images/icon/spruce_wall_sign.png deleted file mode 100644 index 69a9ad9..0000000 Binary files a/viewer/images/icon/spruce_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/warped_hanging_sign.png b/viewer/images/icon/warped_hanging_sign.png deleted file mode 100644 index 80dd99e..0000000 Binary files a/viewer/images/icon/warped_hanging_sign.png and /dev/null differ diff --git a/viewer/images/icon/warped_hanging_wall_sign.png b/viewer/images/icon/warped_hanging_wall_sign.png deleted file mode 100644 index 1519d0b..0000000 Binary files a/viewer/images/icon/warped_hanging_wall_sign.png and /dev/null differ diff --git a/viewer/images/icon/warped_sign.png b/viewer/images/icon/warped_sign.png deleted file mode 100644 index 4c3530b..0000000 Binary files a/viewer/images/icon/warped_sign.png and /dev/null differ diff --git a/viewer/images/icon/warped_wall_sign.png b/viewer/images/icon/warped_wall_sign.png deleted file mode 100644 index 59614c6..0000000 Binary files a/viewer/images/icon/warped_wall_sign.png and /dev/null differ diff --git a/viewer/index.html b/viewer/index.html index caf32a0..20b71b1 100644 --- a/viewer/index.html +++ b/viewer/index.html @@ -4,8 +4,8 @@ MinedMap - - + + diff --git a/viewer/leaflet-1.9.4/images/layers-2x.png b/viewer/leaflet-1.6.0/images/layers-2x.png similarity index 100% rename from viewer/leaflet-1.9.4/images/layers-2x.png rename to viewer/leaflet-1.6.0/images/layers-2x.png diff --git a/viewer/leaflet-1.9.4/images/layers.png b/viewer/leaflet-1.6.0/images/layers.png similarity index 100% rename from viewer/leaflet-1.9.4/images/layers.png rename to viewer/leaflet-1.6.0/images/layers.png diff --git a/viewer/leaflet-1.9.4/images/marker-icon-2x.png b/viewer/leaflet-1.6.0/images/marker-icon-2x.png similarity index 100% rename from viewer/leaflet-1.9.4/images/marker-icon-2x.png rename to viewer/leaflet-1.6.0/images/marker-icon-2x.png diff --git a/viewer/leaflet-1.9.4/images/marker-icon.png b/viewer/leaflet-1.6.0/images/marker-icon.png similarity index 100% rename from viewer/leaflet-1.9.4/images/marker-icon.png rename to viewer/leaflet-1.6.0/images/marker-icon.png diff --git a/viewer/leaflet-1.9.4/images/marker-shadow.png b/viewer/leaflet-1.6.0/images/marker-shadow.png similarity index 100% rename from viewer/leaflet-1.9.4/images/marker-shadow.png rename to viewer/leaflet-1.6.0/images/marker-shadow.png diff --git a/viewer/leaflet-1.9.4/leaflet.css b/viewer/leaflet-1.6.0/leaflet.css similarity index 84% rename from viewer/leaflet-1.9.4/leaflet.css rename to viewer/leaflet-1.6.0/leaflet.css index 2961b76..983d605 100644 --- a/viewer/leaflet-1.9.4/leaflet.css +++ b/viewer/leaflet-1.6.0/leaflet.css @@ -45,10 +45,7 @@ } /* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ /* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ -.leaflet-container .leaflet-overlay-pane svg { - max-width: none !important; - max-height: none !important; - } +.leaflet-container .leaflet-overlay-pane svg, .leaflet-container .leaflet-marker-pane img, .leaflet-container .leaflet-shadow-pane img, .leaflet-container .leaflet-tile-pane img, @@ -56,15 +53,8 @@ .leaflet-container .leaflet-tile { max-width: none !important; max-height: none !important; - width: auto; - padding: 0; } -.leaflet-container img.leaflet-tile { - /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ - mix-blend-mode: plus-lighter; -} - .leaflet-container.leaflet-touch-zoom { -ms-touch-action: pan-x pan-y; touch-action: pan-x pan-y; @@ -176,6 +166,9 @@ /* zoom and fade animations */ +.leaflet-fade-anim .leaflet-tile { + will-change: opacity; + } .leaflet-fade-anim .leaflet-popup { opacity: 0; -webkit-transition: opacity 0.2s linear; @@ -190,10 +183,9 @@ -ms-transform-origin: 0 0; transform-origin: 0 0; } -svg.leaflet-zoom-animated { +.leaflet-zoom-anim .leaflet-zoom-animated { will-change: transform; -} - + } .leaflet-zoom-anim .leaflet-zoom-animated { -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); @@ -259,11 +251,14 @@ svg.leaflet-image-layer.leaflet-interactive path { .leaflet-container { background: #ddd; - outline-offset: 1px; + outline: 0; } .leaflet-container a { color: #0078A8; } +.leaflet-container a.leaflet-active { + outline: 2px solid orange; + } .leaflet-zoom-box { border: 2px dotted #38f; background: rgba(255,255,255,0.5); @@ -272,10 +267,7 @@ svg.leaflet-image-layer.leaflet-interactive path { /* general typography */ .leaflet-container { - font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; - font-size: 12px; - font-size: 0.75rem; - line-height: 1.5; + font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif; } @@ -285,7 +277,8 @@ svg.leaflet-image-layer.leaflet-interactive path { box-shadow: 0 1px 5px rgba(0,0,0,0.65); border-radius: 4px; } -.leaflet-bar a { +.leaflet-bar a, +.leaflet-bar a:hover { background-color: #fff; border-bottom: 1px solid #ccc; width: 26px; @@ -302,8 +295,7 @@ svg.leaflet-image-layer.leaflet-interactive path { background-repeat: no-repeat; display: block; } -.leaflet-bar a:hover, -.leaflet-bar a:focus { +.leaflet-bar a:hover { background-color: #f4f4f4; } .leaflet-bar a:first-child { @@ -393,8 +385,6 @@ svg.leaflet-image-layer.leaflet-interactive path { } .leaflet-control-layers label { display: block; - font-size: 13px; - font-size: 1.08333em; } .leaflet-control-layers-separator { height: 0; @@ -403,7 +393,7 @@ svg.leaflet-image-layer.leaflet-interactive path { } /* Default icon URLs */ -.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ +.leaflet-default-icon-path { background-image: url(images/marker-icon.png); } @@ -412,27 +402,23 @@ svg.leaflet-image-layer.leaflet-interactive path { .leaflet-container .leaflet-control-attribution { background: #fff; - background: rgba(255, 255, 255, 0.8); + background: rgba(255, 255, 255, 0.7); margin: 0; } .leaflet-control-attribution, .leaflet-control-scale-line { padding: 0 5px; color: #333; - line-height: 1.4; } .leaflet-control-attribution a { text-decoration: none; } -.leaflet-control-attribution a:hover, -.leaflet-control-attribution a:focus { +.leaflet-control-attribution a:hover { text-decoration: underline; } -.leaflet-attribution-flag { - display: inline !important; - vertical-align: baseline !important; - width: 1em; - height: 0.6669em; +.leaflet-container .leaflet-control-attribution, +.leaflet-container .leaflet-control-scale { + font-size: 11px; } .leaflet-left .leaflet-control-scale { margin-left: 5px; @@ -445,11 +431,14 @@ svg.leaflet-image-layer.leaflet-interactive path { border-top: none; line-height: 1.1; padding: 2px 5px 1px; + font-size: 11px; white-space: nowrap; + overflow: hidden; -moz-box-sizing: border-box; box-sizing: border-box; - background: rgba(255, 255, 255, 0.8); - text-shadow: 1px 1px #fff; + + background: #fff; + background: rgba(255, 255, 255, 0.5); } .leaflet-control-scale-line:not(:first-child) { border-top: 2px solid #777; @@ -485,22 +474,17 @@ svg.leaflet-image-layer.leaflet-interactive path { border-radius: 12px; } .leaflet-popup-content { - margin: 13px 24px 13px 20px; - line-height: 1.3; - font-size: 13px; - font-size: 1.08333em; - min-height: 1px; + margin: 13px 19px; + line-height: 1.4; } .leaflet-popup-content p { - margin: 17px 0; - margin: 1.3em 0; + margin: 18px 0; } .leaflet-popup-tip-container { width: 40px; height: 20px; position: absolute; left: 50%; - margin-top: -1px; margin-left: -20px; overflow: hidden; pointer-events: none; @@ -511,7 +495,6 @@ svg.leaflet-image-layer.leaflet-interactive path { padding: 1px; margin: -10px auto 0; - pointer-events: auto; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); @@ -528,25 +511,28 @@ svg.leaflet-image-layer.leaflet-interactive path { position: absolute; top: 0; right: 0; + padding: 4px 4px 0 0; border: none; text-align: center; - width: 24px; - height: 24px; - font: 16px/24px Tahoma, Verdana, sans-serif; - color: #757575; + width: 18px; + height: 14px; + font: 16px/14px Tahoma, Verdana, sans-serif; + color: #c3c3c3; text-decoration: none; + font-weight: bold; background: transparent; } -.leaflet-container a.leaflet-popup-close-button:hover, -.leaflet-container a.leaflet-popup-close-button:focus { - color: #585858; +.leaflet-container a.leaflet-popup-close-button:hover { + color: #999; } .leaflet-popup-scrolled { overflow: auto; + border-bottom: 1px solid #ddd; + border-top: 1px solid #ddd; } .leaflet-oldie .leaflet-popup-content-wrapper { - -ms-zoom: 1; + zoom: 1; } .leaflet-oldie .leaflet-popup-tip { width: 24px; @@ -555,6 +541,9 @@ svg.leaflet-image-layer.leaflet-interactive path { -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); } +.leaflet-oldie .leaflet-popup-tip-container { + margin-top: -1px; + } .leaflet-oldie .leaflet-control-zoom, .leaflet-oldie .leaflet-control-layers, @@ -589,7 +578,7 @@ svg.leaflet-image-layer.leaflet-interactive path { pointer-events: none; box-shadow: 0 1px 3px rgba(0,0,0,0.4); } -.leaflet-tooltip.leaflet-interactive { +.leaflet-tooltip.leaflet-clickable { cursor: pointer; pointer-events: auto; } @@ -649,13 +638,3 @@ svg.leaflet-image-layer.leaflet-interactive path { margin-left: -12px; border-right-color: #fff; } - -/* Printing */ - -@media print { - /* Prevent printers from removing background-images of controls. */ - .leaflet-control { - -webkit-print-color-adjust: exact; - print-color-adjust: exact; - } - } diff --git a/viewer/leaflet-1.6.0/leaflet.js b/viewer/leaflet-1.6.0/leaflet.js new file mode 100644 index 0000000..bc9ef0f --- /dev/null +++ b/viewer/leaflet-1.6.0/leaflet.js @@ -0,0 +1,5 @@ +/* @preserve + * Leaflet 1.6.0+Detached: 0c81bdf904d864fd12a286e3d1979f47aba17991.0c81bdf, a JS library for interactive maps. http://leafletjs.com + * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";var i=Object.freeze;function h(t){var i,e,n,o;for(e=1,n=arguments.length;e=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.xi.y&&n.y=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lati.lng&&n.lng';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function Bt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var At=(Object.freeze||Object)({ie:it,ielt9:et,edge:nt,webkit:ot,android:st,android23:rt,androidStock:ht,opera:ut,chrome:lt,gecko:ct,safari:_t,phantom:dt,opera12:pt,win:mt,ie3d:ft,webkit3d:gt,gecko3d:vt,any3d:yt,mobile:xt,mobileWebkit:wt,mobileWebkit3d:Pt,msPointer:Lt,pointer:bt,touch:Tt,mobileOpera:zt,mobileGecko:Mt,retina:Ct,passiveEvents:Et,canvas:St,svg:Zt,vml:kt}),It=Lt?"MSPointerDown":"pointerdown",Ot=Lt?"MSPointerMove":"pointermove",Rt=Lt?"MSPointerUp":"pointerup",Nt=Lt?"MSPointerCancel":"pointercancel",Dt=["INPUT","SELECT","OPTION"],jt={},Wt=!1,Ht=0;function Ft(t,i,e,n){return"touchstart"===i?function(t,i,e){var n=a(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(Dt.indexOf(t.target.tagName)<0))return;ji(t)}Gt(t,i)});t["_leaflet_touchstart"+e]=n,t.addEventListener(It,n,!1),Wt||(document.documentElement.addEventListener(It,Ut,!0),document.documentElement.addEventListener(Ot,Vt,!0),document.documentElement.addEventListener(Rt,qt,!0),document.documentElement.addEventListener(Nt,qt,!0),Wt=!0)}(t,e,n):"touchmove"===i?function(t,i,e){function n(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&Gt(t,i)}t["_leaflet_touchmove"+e]=n,t.addEventListener(Ot,n,!1)}(t,e,n):"touchend"===i&&function(t,i,e){function n(t){Gt(t,i)}t["_leaflet_touchend"+e]=n,t.addEventListener(Rt,n,!1),t.addEventListener(Nt,n,!1)}(t,e,n),this}function Ut(t){jt[t.pointerId]=t,Ht++}function Vt(t){jt[t.pointerId]&&(jt[t.pointerId]=t)}function qt(t){delete jt[t.pointerId],Ht--}function Gt(t,i){for(var e in t.touches=[],jt)t.touches.push(jt[e]);t.changedTouches=[t],i(t)}var Kt=Lt?"MSPointerDown":bt?"pointerdown":"touchstart",Yt=Lt?"MSPointerUp":bt?"pointerup":"touchend",Xt="_leaflet_";function Jt(t,o,i){var s,r,a=!1;function e(t){var i;if(bt){if(!nt||"mouse"===t.pointerType)return;i=Ht}else i=t.touches.length;if(!(1this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,D(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e=I((i=i||{}).paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getCenter(),s=this.project(o),r=this.project(t),a=this.getPixelBounds(),h=a.getSize().divideBy(2),u=R([a.min.add(e),a.max.subtract(n)]);if(!u.contains(r)){this._enforcingBounds=!0;var l=s.subtract(r),c=I(r.x+l.x,r.y+l.y);(r.xu.max.x)&&(c.x=s.x-l.x,0u.max.y)&&(c.y=s.y-l.y,0=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[u(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Yi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Yi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!Ki(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Mi(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){if("click"===t.type){var n=h({},t);n.type="preclick",this._fireDOMEvent(n,n.type,e)}if(!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&ji(t);var s={originalEvent:t};if("keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type){var r=o.getLatLng&&(!o._radius||o._radius<=10);s.containerPoint=r?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),s.layerPoint=this.containerPointToLayerPoint(s.containerPoint),s.latlng=r?o.getLatLng():this.layerPointToLatLng(s.layerPoint)}for(var a=0;athis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,mi(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&fi(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Qi(t){return new te(t)}var te=S.extend({options:{position:"topright"},initialize:function(t){p(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return mi(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(li(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+u(this),n),this._layerControlInputs.push(i),i.layerId=u(t.layer),ki(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;si.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),ee=te.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"−",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=ui("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ui("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Di(s),ki(s,"click",Wi),ki(s,"click",o,this),ki(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";fi(this._zoomInButton,i),fi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||mi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||mi(this._zoomInButton,i)}});$i.mergeOptions({zoomControl:!0}),$i.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new ee,this.addControl(this.zoomControl))});var ne=te.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=ui("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ui("div",i,e)),t.imperial&&(this._iScale=ui("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280Leaflet'},initialize:function(t){p(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=ui("div","leaflet-control-attribution"),Di(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});$i.mergeOptions({attributionControl:!0}),$i.addInitHook(function(){this.options.attributionControl&&(new oe).addTo(this)});te.Layers=ie,te.Zoom=ee,te.Scale=ne,te.Attribution=oe,Qi.layers=function(t,i,e){return new ie(t,i,e)},Qi.zoom=function(t){return new ee(t)},Qi.scale=function(t){return new ne(t)},Qi.attribution=function(t){return new oe(t)};var se=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});se.addTo=function(t,i){return t.addHandler(i,this),this};var re,ae={Events:Z},he=Tt?"touchstart mousedown":"mousedown",ue={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},le={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ce=k.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){p(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(ki(this._dragStartTarget,he,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ce._dragging===this&&this.finishDrag(),Ai(this._dragStartTarget,he,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!pi(this._element,"leaflet-zoom-anim")&&!(ce._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ce._dragging=this)._preventOutline&&Mi(this._element),Ti(),Qt(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t,e=Ei(this._element);this._startPoint=new B(i.clientX,i.clientY),this._parentScale=Si(e),ki(document,le[t.type],this._onMove,this),ki(document,ue[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled)if(t.touches&&1i.max.x&&(e|=2),t.yi.max.y&&(e|=8),e}function ge(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||je.prototype._containsPoint.call(this,t,!0)}});var He=ke.extend({initialize:function(t,i){p(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=v(t)?t:t.features;if(o){for(i=0,e=o.length;iu.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Wi(t)},_getAnchor:function(){return I(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});$i.mergeOptions({closePopupOnClick:!0}),$i.include({openPopup:function(t,i,e){return t instanceof sn||(t=new sn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Se.include({bindPopup:function(t,i){return t instanceof sn?(p(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new sn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Wi(t),i instanceof Re?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var rn=on.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){on.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){on.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=on.prototype.getEvents.call(this);return Tt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=ui("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=I(this.options.offset),u=this._getAnchor();t="top"===s?t.add(I(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t.subtract(I(r/2-h.x,-h.y,!0)):"center"===s?t.subtract(I(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.xthis.options.maxZoom||ethis.options.maxZoom||void 0!==this.options.minZoom&&oe.max.x)||!i.wrapLat&&(t.ye.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return D(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new N(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new B(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(li(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){mi(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=l,t.onmousemove=l,et&&this.options.opacity<1&&yi(t,this.options.opacity),st&&!rt&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(a(this._tileReady,this,t,null,o)),Pi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(yi(e.el,0),C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(mi(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),et||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new B(this._wrapX?r(t.x,this._wrapX):t.x,this._wrapY?r(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new O(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var un=hn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=p(this,i)).detectRetina&&Ct&&0')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),fn={_initContainer:function(){this._container=ui("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(_n.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=mn("shape");mi(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=mn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;li(i),t.removeInteractiveTarget(i),delete this._layers[u(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=mn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=v(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=mn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){_i(t._container)},_bringToBack:function(t){di(t._container)}},gn=kt?mn:$,vn=_n.extend({getEvents:function(){var t=_n.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=gn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=gn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){li(this._container),Ai(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){_n.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),Pi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=gn("path");t.options.className&&mi(i,t.options.className),t.options.interactive&&mi(i,"leaflet-interactive"),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){li(t._path),t.removeInteractiveTarget(t._path),delete this._layers[u(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,Q(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){_i(t._path)},_bringToBack:function(t){di(t._path)}});function yn(t){return Zt||kt?new vn(t):null}kt&&vn.include(fn),$i.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this._createRenderer()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&pn(t)||yn(t)}});var xn=We.extend({initialize:function(t,i){We.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=D(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});vn.create=gn,vn.pointsToPath=Q,He.geometryToLayer=Fe,He.coordsToLatLng=Ve,He.coordsToLatLngs=qe,He.latLngToCoords=Ge,He.latLngsToCoords=Ke,He.getFeature=Ye,He.asFeature=Xe,$i.mergeOptions({boxZoom:!0});var wn=se.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){ki(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Ai(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){li(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Qt(),Ti(),this._startPoint=this._map.mouseEventToContainerPoint(t),ki(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ui("div","leaflet-zoom-box",this._container),mi(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new O(this._point,this._startPoint),e=i.getSize();Pi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(li(this._box),fi(this._container,"leaflet-crosshair")),ti(),zi(),Ai(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0);var i=new N(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});$i.addInitHook("addHandler","boxZoom",wn),$i.mergeOptions({doubleClickZoom:!0});var Pn=se.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});$i.addInitHook("addHandler","doubleClickZoom",Pn),$i.mergeOptions({dragging:!0,inertia:!rt,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var Ln=se.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new ce(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}mi(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){fi(this._map._container,"leaflet-grab"),fi(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=D(this._map.options.maxBounds);this._offsetLimit=R(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),this._prunePositions(i)}this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)i.getMaxZoom()&&1=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1